组播又称为多播,相对于广播更受程序员们的欢迎,但是介于很多平台对组播的支持不是很好的缘故,很多程序员像我一样不得不放弃组播,选择广播。大家都知道广播是无法跨路由的,只有在同一广播域内的机器才能收到该广播域内来自其他其他机器的广播包。广播还有一个很大的缺点就是不做过滤,同一广播域内的所有机器都会收到广播包,不管机器是否愿意。这对不关心该广播包的机器而言就是垃圾数据,无形中造成了网络拥塞。这也是很多程序员实在不想采用广播的原因。然而多播就可爱多了,它不仅可以跨路由,而且只对加入了相同组播域的机器发数据。也就是说,如果哪台机器关心来自某一组播域的数据,它必须主动加入该组播域,执行加入指令以后,系统会向路由发送一条加入请求,路由会在该组播域上维护新加入机器的套接字(文件描述符),当路由收到其他机器发到该组播域的数据以后,会依次转发到已经加入改组播域的所有套接字(文件描述符)中去。
你的机器有几个可用的网络接口,一般就只有几个可用广播域。然而可用组播域就很多了,从224.0.0.0到239.255.255.255之间的IP地址都可以作为组播域。
下面就给出一套实例。
一、服务端server负责往组播域“224.0.1.1”发送组播包。
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <arpa/inet.h> #define MAXBUF 256 int port=7083; char *multicast_addr= "224.0.1.1"; int main(int argc, char *argv[]) { int s; char buf[MAXBUF]; struct sockaddr_in srv; bzero(&srv,sizeof(srv)); srv.sin_family=AF_INET; srv.sin_addr.s_addr=inet_addr(multicast_addr); srv.sin_port=htons(port); s=socket(AF_INET,SOCK_DGRAM,0); if( s < 0 ) { perror( "Opening socket "); return 0; } while(1) { fgets(buf,MAXBUF,stdin); if(sendto(s,buf,strlen(buf),0,(struct sockaddr*)&srv,sizeof(srv)) <0) { perror( "sendto "); return 0; } else { fprintf(stdout, "send to group %s : %s\n ",multicast_addr, buf); } } return 1; }
二、客服段client负责接收来自组播域“224.0.1.1”的组播数据。
#include <stdio.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #define MAXBUF 256 int port = 7083; char *multicast_addr = "224.0.1.1"; int main(int argc, char *argv[]) { int s,n; int reuse = 1; struct sockaddr_in srv,cli; int cli_len = sizeof(cli); struct ip_mreq mreq; char buf[MAXBUF]; bzero(&srv,sizeof(srv)); srv.sin_family=AF_INET; srv.sin_addr.s_addr=htonl(INADDR_ANY); srv.sin_port=htons(port); if((s=socket(AF_INET,SOCK_DGRAM,0)) < 0) { perror("Opening socket "); return 0; } mreq.imr_multiaddr.s_addr=inet_addr(multicast_addr); mreq.imr_interface.s_addr=htonl(INADDR_ANY); if(setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { perror("setsockopt: IP_ADD_MEMBERSHIP "); return 0; } if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { perror("setsockopt: SO_REUSEADDR "); return 0; } if(bind(s, (struct sockaddr*)&srv, sizeof(srv)) < 0) { perror("bind "); return 0; } while(1) { if((n=recvfrom(s, buf, MAXBUF, 0, (struct sockaddr*)&cli, &cli_len)) < 0) { perror("recvfrom "); return 0; } else { buf[n]=0; fprintf(stdout, " receive msg from %s : %s\n",inet_ntoa(cli.sin_addr),buf); } } return 1; }
除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。