首页 > 系统相关 >Linux网络编程——多播

Linux网络编程——多播

时间:2022-09-28 21:44:30浏览次数:157  
标签:多播 addr 224.0 IP 编程 地址 Linux include


概述

单播用于两个主机之间的端对端通信,广播用于一个主机对整个局域网上所有主机上的数据通信。单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是多播的用途。


IP 多播(也称多址广播或组播)技术,是一种允许一台或多台主机(多播源)发送单一数据包到多台主机(一次的,同时的)的 TCP/IP 网络技术。多播是 IPv6 数据包的 3 种基本目的地址类型之一,多播是一点对多点的通信, IPv6 没有采用 IPv4 中的组播术语,而是将广播看成是多播的一个特殊例子


多播作为一点对多点的通信,数据的收发仅仅在同一分组中进行,是节省网络带宽的有效方法之一。在网络应用中,当需要将一个节点的信号传送到多个节点时,无论是采用重复点对点通信方式,还是采用广播方式,都会严重浪费网络带宽,只有多播才是最好的选择。多播能使一个或多个多播源只把数据包发送给特定的多播组,而只有加入该多播组的主机才能接收到数据包。


IP 多播应用大致可以分为三类:点对多点应用,多点对点应用和多点对多点应用。

1)点对多点应用是指一个发送者,多个接收者的应用形式,这是最常见的多播应用形式。典型的应用包括:媒体广播、媒体推送、信息缓存、事件通知和状态监视等。

2)多点对点应用是指多个发送者,一个接收者的应用形式。通常是双向请求响应应用,任何一端(多点或点)都有可能发起请求。典型应用包括:资源查找、数据收集、网络竞拍、信息询问等。

3)多点对多点应用是指多个发送者和多个接收者的应用形式。通常,每个接收者可以接收多个发送者发送的数据,同时,每个发送者可以把数据发送给多个接收者。典型应用包括:多点会议、资源同步、并行处理、协同处理、远程学习、讨论组、分布式交互模拟(DIS)、多人游戏等。


多播地址

IP 多播通信必须依赖于 IP 多播地址,在 IPv4 中它是一个 D 类 IP 地址,范围从 224.0.0.0 到 239.255.255.255,并被划分为局部链接多播地址、预留多播地址和管理权限多播地址三类:

1)局部链接多播地址范围在 224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;

2)预留多播地址为 224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议;

3)管理权限多播地址为 239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有 IP 地址,不能用于 Internet,可限制多播范围。


一些多播组地址被 IANA 确定为知名地址,它们也被当作永久主机组,这和 TCP 及 UDP 中的知名端口相似。同样,这些知名多播地址在 RFC 最新分配数字中列出,注意这些多播地址所代表的组是永久组,而它们的组成员却不是永久的。这些地址如下:

224.0.0.1    所有组播主机

224.0.0.2    所有组播路由器

224.0.0.4    DRMRP 路由器

224.0.0.5    所有 OSPF 的路由器

224.0.0.6    OSPF 指派路由器

224.0.0.9    RPIv2 路由器

224.0.0.10  EIGRP 路由器

224.0.0.13  PIM 路由器

224.0.0.22  IGMPv3

224.0.0.25  RGMP

224.0.1.1    NTP 网络时间协议


多播地址与 MAC 地址的映射

使用同一个 IP 多播地址接收多播数据包的所有主机构成了一个主机组,也称为多播组。一个多播组的成员是随时变动的,一台主机可以随时加入或离开多播组,多播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个多播组。


这个我们可以这样理解,多播地址就类似于 QQ 群号,多播组相当于 QQ 群,一个个的主机就相当于群里面的成员


 IPv4 的 D 类地址是多播地址。IEEE 把一块以太网多播组地址分给 IANA 以支持IP多播。块的地址都以 01:00:5e 开头,第 25 位为 0,低 23 位为 IPv4 多播地址( D类地址 )的低 23 位。IPv4 多播地址与 MAC 地址的映射关系如图所示:

Linux网络编程——多播_网络编程


由于多播地址( D类地址 )中的最高 5bit 在映射过程中被忽略,因此每个以太网多播地址对应的多播组是不唯一的。32 个不同的多播组号被映射为一个以太网地址。例如,多播地址 224.128.64.32(十六进制 e0.80.40.20)和 224.0.64.32(十六进制 e0.00.40.20)都映射为同一以太网地址 01:00:5e:00:40:20。


既然地址映射是不唯一的,那么设备驱动程序或 IP 层就必须对数据报进行过滤。因为网卡可能接收到主机不想接收的多播数据帧,如下图,假如主机 1 加入的多播为 224.128.64.32, 主机 2 加入的多播为 224.0.64.32,我们想给 224.0.64.32 所在的多播组 ( 主机 2 ) 发送信息,数据经过网卡时,224.128.64.32 (主机 1 ) 和 224.0.64.32 (主机 2 ) 所在多播组的网卡都会收到数据,因为它们的 MAC 地址都是 01:00:5e:00:40:20。这时候,如果网卡不提供足够的多播数据帧过滤功能,设备驱动程序就必须接收所有多播数据帧,然后对它们进行过滤,这个过滤过程是网络驱动或IP层自动完成。

Linux网络编程——多播_网络编程_02

Linux多播编程

套接口选项

int setsockopt( int sockfd, int level,int optname,   

const void *optval, socklen_t optlen );

Linux网络编程——多播_多点_03



成功执行返回0,否则返回-1


选项 IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP

加入或者退出一个多播组,通过选项 IP_ADD_MEMBERSHIP 和 IP_DROP_MEMBERSHIP,对一个结构 struct ip_mreq 类型的变量进行控制,struct ip_mreq 原型如下:

struct in_addr
{

in_addr_t s_addr;

}


struct ip_mreq          

struct in_addr imn_multiaddr; // 多播组 IP,类似于 QQ 群号

struct in_addr imr_interface;   // 将要添加到多播组的 IP,类似于QQ 成员号

};


多播只能用 UDP 或原始 IP 实现,不能用 TCP。


加入多播实例:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

int main(int argc, char*argv[])
{
int sockfd; // 套接字文件描述符
struct sockaddr_in local_addr; // 本地地址
int err = -1;
char group[16] = "224.0.0.88"; // 多播组 IP

sockfd = socket(AF_INET, SOCK_DGRAM, 0); //建立套接字
if (sockfd == -1)
{
perror("socket()");
return -1;
}

// 初始化地址
memset(&local_addr, 0, sizeof(local_addr));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
local_addr.sin_port = htons(8000);

// 绑定socket
err = bind(sockfd,(struct sockaddr*)&local_addr, sizeof(local_addr));
if(err < 0)
{
perror("bind()");
return -2;
}

struct ip_mreq mreq; // 多播地址结构体

// 加入多播组,相当于创建一个QQ群,某人加入此群
mreq.imr_multiaddr.s_addr = inet_addr(group); // 多播地址,类似于 QQ 群号
mreq.imr_interface.s_addr = htonl(INADDR_ANY);// 将本机加入多播组,类似于某人加入此群
// 加入多播组
err = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq));
if (err < 0)
{
perror("setsockopt():IP_ADD_MEMBERSHIP");
return -4;
}

int times = 0;
int addr_len = 0;
char buff[256] = {0};
int n = 0;

// 循环接收广播组的消息,5次后退出
for(times = 0; times<5; times++)
{
addr_len = sizeof(local_addr);
memset(buff, 0, sizeof(buff));

// 接收数据
n = recvfrom(sockfd, buff, sizeof(buff), 0,(struct sockaddr*)&local_addr, &addr_len);
if( n== -1)
{
perror("recvfrom()");
}

printf("Recv %dst message from server:%s\n", times, buff);
sleep(2);
}

// 退出广播组
err = setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof(mreq));

close(sockfd);

return 0;
}


以上代码编译运行时,可以会出现这样的错误:No such device。这主要和网络配置有关,解决方法请点此

向多播组发送信息的测试示例:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

int main(int argc, char*argv)
{
int sockfd; // 套接字文件描述符
struct sockaddr_in dest_addr; // 目标ip
char buf[] = "BROADCAST TEST DATA";

sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 建立套接字
if (s == -1)
{
perror("socket()");
return -1;
}

// 初始化目标 ip 信息
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr("224.0.0.88"); // 目的地址,为多播地址
dest_addr.sin_port = htons(8000); // 多播服务器的端口也是 8000

// 向多播地址发送数据
while(1){
int n = sendto(sockfd, buf, strlen(buf), 0,(struct sockaddr*)&dest_addr, sizeof(dest_addr));
if( n < 0)
{
perror("sendto()");
return -2;
}

sleep(1);
}

return 0;
}


标签:多播,addr,224.0,IP,编程,地址,Linux,include
From: https://blog.51cto.com/u_3002289/5720936

相关文章

  • Linux网络编程——绑定( bind )端口需要注意的问题
    所谓绑定(bind)是指别人连接我只能通过我所绑定的端口,相当于,我买了一个手机,别人要想联系我,必须要知道我的手机号码,这时候,我需要怎么办呢?我需要给手机插上电话卡,固定一个电话......
  • Linux开发环境搭建与使用——通过虚拟机安装系统( ubuntu )
    双击VMware-player-4.0.6-1035888.exe,一路next即可。通过VmwarePlayer创建虚拟机第一步第二步第三步第四步第五步第六步第七步此时已新建好虚拟机,再配置下虚拟机就可以在虚......
  • Linux 开发环境搭建与使用——Linux 编译器之 GCC
    ​​上一节我们学习了vim编辑器​​,接下来我们一起学习gcc编译器,这里,我们要区分编辑器和编译器有何不同?编辑器是指我用它来写程序的(编辑代码),而我们写的代码语句,电脑是不......
  • Linux 开发环境搭建与使用——Linux 常用编辑器之vim
    概述vi编辑器是Linux系统中最常用的文本编辑器,vi在Linux界有编辑器之神的美誉几乎所有的Linux发行版中都包含vi程序。vi工作在字符模式下,不需要图形界面,非常适合......
  • Linux 网络编程——原始套接字实例:MAC 地址扫描器
    如果A(192.168.1.1)向B(192.168.1.2)发送一个数据包,那么需要的条件有ip、port、使用的协议(TCP/UDP)之外还需要MAC地址,因为在以太网数据包中MAC地址是必须要有的。那么......
  • Linux 网络编程——IP 数据报格式详解
    IP数据报首部TCP/IP协议定义了一个在因特网上传输的包,称为IP数据报(IPDatagram)。这是一个与硬件无关的虚拟包,由首部和数据两部分组成。首部的前一部分是固定长度,共2......
  • Linux 网络编程—— libpcap 详解
    概述libpcap是一个网络数据包捕获函数库,功能非常强大,Linux下著名的tcpdump就是以它为基础的。libpcap主要的作用1)捕获各种数据包,列如:网络流量统计。2)过滤网络数据包,列如......
  • Linux 网络编程——TCP 和 UDP 数据报格式详解
    TCP报文格式TCP(TransmissionControlProtocol传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP报文段的报头有10个必需的字段和1个可选字段......
  • Linux网络编程——原始套接字实例:MAC 头部报文分析
    ​​通过《Linux网络编程——原始套接字编程》得知​​,我们可以通过原始套接字以及 recvfrom()可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢?MAC头......
  • Linux系统编程——线程同步与互斥:互斥锁
    为什么需要互斥锁?在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在......