组播可以看成是单播和广播的折中。当发送组播数据包时,只有加入指定多播组的主机数据链路层才会处理,其他主机在数据链路层会直接丢掉收到的数据包。即我们可以通过组播的方式和指定的若干台主机通信。
D类地址:范围从224.0.0.1到239.255.255.254.此类地址又称为组播地址。每个组播地址代表一个多播组。
组播包的发送和接收通过UDP套接字实现。
组播包发送流程如下:
(1)创建UDP套接字;socket(AF_INET, SOCK_DGRAM, 0)
(2)指定目标地址和端口;struct sockaddr_in
(3)发送数据包;sendto( )
send.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <arpa/inet.h> 7 #include <netinet/in.h> 8 #include <string.h> 9 10 #define err_log(log) do{perror(log); exit(1);}while(0) 11 12 #define N 128 13 14 int main(int argc, const char *argv[]) 15 { 16 17 int sockfd; 18 struct sockaddr_in groupcastaddr; 19 char buf[N] = {0}; 20 21 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 22 { 23 err_log("fail to socket"); 24 } 25 26 groupcastaddr.sin_family = AF_INET; 27 groupcastaddr.sin_addr.s_addr = inet_addr("225.0.0.3"); 28 groupcastaddr.sin_port = htons(10000); 29 30 while(1) 31 { 32 printf("Input > "); 33 fgets(buf, N, stdin); 34 if(sendto(sockfd,buf, N, 0, (struct sockaddr *)&groupcastaddr, sizeof(groupcastaddr)) < 0) 35 { 36 err_log("fail to sendto"); 37 } 38 39 } 40 41 return 0; 42 }
组播接收流程如下:
(1)创建UDP套接字;socket(AF_INET, SOCK_DGRAM, 0)
(2)加入多播组;setsockopt( )
(3)填充组播地址信息(组播IP地址和端口);struct sockaddr_in
(4)接收数据包;recvfrom( )
多播结构体:
1 struct ip_mreq 2 { 3 /* IP multicast address of group. */ 组播的ip地址 4 struct in_addr imr_multiaddr; 5 6 /* Local IP address of interface. */ 本机的ip地址 7 struct in_addr imr_interface; 8 }; 9 10 mreq.imr_multiaddr.s_addr = inet_addr(“224.10.10.1”); //组播地址 11 mreq.imr_interface.s_addr = htonl(INADDR_ANY); //INADDR_ANY 0 地址 ,任意的主机地址 12 13 setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
recv.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <arpa/inet.h> 7 #include <netinet/in.h> 8 #include <string.h> 9 10 #define err_log(log) do{perror(log); exit(1);}while(0) 11 #define N 128 12 13 int main(int argc, const char *argv[]) 14 { 15 16 int sockfd; 17 char buf[N]; 18 struct sockaddr_in groupcastaddr, srcaddr; 19 struct ip_mreq mreq; 20 21 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 22 { 23 err_log("fail to socket"); 24 } 25 /*为套接字绑定组播地址和端口*/ 26 groupcastaddr.sin_family = AF_INET; 27 groupcastaddr.sin_addr.s_addr = inet_addr("225.0.0.3"); 28 groupcastaddr.sin_port = htons(10000); 29 30 /*加入多播组,允许数据链路层处理指定组播包*/ 31 mreq.imr_multiaddr.s_addr = inet_addr("225.0.0.3"); 32 mreq.imr_interface.s_addr = htonl(INADDR_ANY); 33 34 if(setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) < 0) 35 { 36 err_log("fail to setsockopt"); 37 } 38 39 int on = 1; 40 if(setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 41 { 42 err_log("fail to setsockopt"); 43 } 44 45 if(bind(sockfd, (struct sockaddr*)&groupcastaddr, sizeof(groupcastaddr)) < 0) 46 { 47 err_log("fail to bind"); 48 } 49 50 socklen_t addrlen = sizeof(struct sockaddr); 51 52 while(1) 53 { 54 if(recvfrom(sockfd,buf, N, 0, (struct sockaddr *)&srcaddr, &addrlen) < 0) 55 { 56 err_log("fail to sendto"); 57 } 58 printf("buf:%s ---> %s %d ", buf, inet_ntoa(srcaddr.sin_addr), ntohs(srcaddr.sin_port)); 59 } 60 61 return 0; 62 }