Linux网络编程|UNP学习_组播服务器与客户端的实现

UNP学习_组播服务器与客户端的实现
1.1 组播概述
??组播是一种介于单播和广播之间的方案,多播地址表示一组主机IP接口,多拨数据报只由对他感兴趣的接口接收。组播可以在Internet和局域网使用。一个多播地址和一个UDP端口的组合称为组播会话(session)。
1.2 组播地址
【Linux网络编程|UNP学习_组播服务器与客户端的实现】1.2.1 IPv4的D类地址
??IPv4的D类地址(224.0.0.0到239.255.255.255)是IPv4的组播地址。D类地址的低28位称为组ID(group ID),完整32位称为组地址(group address)。下面是几个特殊的IPv4组播地址:
(1)224.0.0.1是所有节点组。子网上所有具有组播能力的节点(主机、路由器等)必须在具有组播能力的接口上加入该组。
(2)224.0.0.2是所有路由器组。子网上所有组播路由器必须在具有多播能力的接口上加入该组。
(3)介于224.0.0.0到224.0.0.255之间的地址(224.0.0.0/24)称为链路局部的组播地址,这些地址为低级拓扑发现和维护协议保留,路由器冲不转发以这些地址为目的地址的数据报。
1.2.2 IPv6组播地址
??IPv6的组播地址的高字节值为ff。IPv6的组播地址有2种格式,详见UNP434页。下面是两个特殊的IPv6组播地址
(1)ff01::1和ff02::1是所有节点组。
(2)ff01::2、ff02::2和ff05::2是所有路由器组
IPV6组播地址还存在一个4位的范围,用于指定组播数据报能够游走的范围。还有一个跳限字段,用于限制分组被路由转发的次数。
Linux网络编程|UNP学习_组播服务器与客户端的实现
文章图片

Linux网络编程|UNP学习_组播服务器与客户端的实现
文章图片

1.3 局域网上的组播示例
Linux网络编程|UNP学习_组播服务器与客户端的实现
文章图片

??右侧主机上的接收进程启动,并创建一个UDP套接字,捆绑端口123到该套接字上,然后加入多播组224.0.1.1。IPv4层内部保存这些信息,并告知合适的数据链路接收目的地址为01:00:53:00:01:01的以太网帧。该地址是与接收应用进程加入的组播IP地址对应的以太网地址,映射方法如21-1图所示,此处详细情况见UNP的P437。
2.1 局域网UDP组播服务器的实现

// File Name: multicast_server.c // Author: AlexanderGan // Created Time: 2020年08月11日 星期二 19时57分33秒#include #include #include #include #include #include #include #include #includeint main(int argc, char*argv[]){int fd = socket(AF_INET,SOCK_DGRAM,0); if(fd < 0){ perror("socket error!\n"); exit(1); }struct sockaddr_in serv_addr, client_addr; socklen_t serv_len = sizeof(serv_addr); socklen_t cli_len = sizeof(client_addr); memset(&serv_addr,0,serv_len); memset(&client_addr,0,cli_len); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(4321); //server端口int ret = bind(fd,(struct sockaddr*)&serv_addr,serv_len); if(ret < 0){ perror("bind error!\n"); exit(1); } //初始化客户端信息 client_addr.sin_family = AF_INET; client_addr.sin_port = htons(2222); //客户端需要绑定的端口 //组播需要的地址 inet_pton(AF_INET,"239.0.0.10", &client_addr.sin_addr.s_addr); //打开服务器组播权限 struct ip_mreqn flag; //init flag inet_pton(AF_INET,"239.0.0.10",&flag.imr_multiaddr.s_addr); //广播地址 inet_pton(AF_INET,"0.0.0.0",&flag.imr_address.s_addr); //本地IP flag.imr_ifindex = if_nametoindex("ens33"); setsockopt(fd,IPPROTO_IP, IP_MULTICAST_IF,&flag,sizeof(flag)); //通信 while(1){ //持续给客户端广播数据 static int num = 0; char buf[4096] = {0}; sprintf(buf,"hello ,udp_id == %d\n",num++); int send_len = sendto(fd,buf,sizeof(buf),0,(struct sockaddr*)&client_addr,cli_len); if(send_len < 0){ perror("send error!\n"); exit(1); }printf("send buf = %s\n",buf); sleep(1); /*char ip[64]; printf("New Client IP : %s, port = %d\n", inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,ip,sizeof(ip)), ntohs(client_addr.sin_port)); sendto(fd,buf,strlen(buf)+1,0,(struct sockaddr*)&client_addr,cli_len); */} close(fd); return 0 ; }

3.1 局域网UDP组播客户端的实现
// File Name: multicast_client.c // Author: AlexanderGan // Created Time: 2020年08月16日 星期日 19时06分28秒 // 组播客户端#include #include #include #include #include #include #include #include #include int main(int argc, char*argv[]){int fd = socket(AF_INET,SOCK_DGRAM,0); if(fd < 0){ perror("socket error!\n"); exit(1); } //绑定IP和端口 struct sockaddr_in serv_addr, client_addr; socklen_t serv_len = sizeof(serv_addr); socklen_t cli_len = sizeof(client_addr); memset(&client_addr,0,cli_len); client_addr.sin_family = AF_INET; client_addr.sin_port = htons(2222); inet_pton(AF_INET,"0.0.0.0",&client_addr.sin_addr.s_addr); int ret = bind(fd,(struct sockaddr*)&client_addr,cli_len); if(ret < 0){ perror("bind error!\n"); exit(1); }//加入到组播地址 struct ip_mreqn flag; inet_pton(AF_INET,"239.0.0.10",&flag.imr_multiaddr.s_addr); inet_pton(AF_INET,"0.0.0.0",&flag.imr_address.s_addr); flag.imr_ifindex = if_nametoindex("ens33"); setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&flag,sizeof(flag)); //通信 while(1){ char buf[1024]; int recv = recvfrom(fd,buf,sizeof(buf),0,NULL,NULL); if(recv < 0) { perror("recv error!\n"); break; }printf("client recv buf =%s\n",buf); }close(fd); return 0; }

4.1 组播的优点:
(1)组播利用多数网卡都提供的硬件过滤减少非期望分组的接收,硬件过滤在链路层就丢弃掉非期望的数据,还降低了不参与多播应用的系统的其他主机的负荷。
(2)组播可以在局域网上使用,也可以在因特网上使用。

    推荐阅读