组播可以看成是单播和广播的折中。当发送组播数据包时,只有加入指定多播组的主机数据链路层才会处理,其他主机在数据链路层会直接丢掉收到的数据包。即我们可以通过组播的方式和指定的若干台主机通信。
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 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 #define err_log(log) do{perror(log); exit(1);}while(0)11 12 #define N 12813 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 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 #define err_log(log) do{perror(log); exit(1);}while(0)11 #define N 12812 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\n", buf, inet_ntoa(srcaddr.sin_addr), ntohs(srcaddr.sin_port));59 }60 61 return 0;62 }