Linux 多播例子 及修正

/*下面这个例子转自http://book.51cto.com/art/200912/168572.htm, 稍后会对这个例子进行修正*/

 一个多播例子的服务器端

下面是一个多播服务器的例子。多播服务器的程序设计很简单,建立一个数据包套接字,选定多播的IP地址和端口,直接向此多播地址发送数据就可以了。多播服务器的程序设计,不需要服务器加入多播组,可以直接向某个多播组发送数据。


下面的例子持续向多播IP地址"224.0.0.88"的8888端口发送数据"BROADCAST TEST DATA",每发送一次间隔5s。(这个IP应该是用于局域网的)

  1. /*  
  2. *broadcast_server.c - 多播服务程序  
  3. */  
  4. #define MCAST_PORT 8888;  
  5. #define MCAST_ADDR "224.0.0.88"/    /*一个局部连接多播地址,路由器不进行转发*/  
  6. #define MCAST_DATA "BROADCAST TEST DATA"            /*多播发送的数据*  
  7. #define MCAST_INTERVAL 5                            /*发送间隔时间*/  
  8. int main(int argc, char*argv)  
  9. {  
  10.     int s;  
  11.     struct sockaddr_in mcast_addr;        
  12.     s = socket(AF_INET, SOCK_DGRAM, 0);         /*建立套接字*/  
  13.     if (s == -1)  
  14.     {  
  15.         perror("socket()");  
  16.         return -1;  
  17.     }  
  18.       
  19.     memset(&mcast_addr, 0, sizeof(mcast_addr));/*初始化IP多播地址为0*/  
  20.     mcast_addr.sin_family = AF_INET;                /*设置协议族类行为AF*/  
  21.     mcast_addr.sin_addr.s_addr = inet_addr(MCAST_ADDR);/*设置多播IP地址*/  
  22.     mcast_addr.sin_port = htons(MCAST_PORT);        /*设置多播端口*/  
  23.       
  24.                                                     /*向多播地址发送数据*/  
  25.     while(1) {  
  26.         int n = sendto(s,                           /*套接字描述符*/  
  27.                                     MCAST_DATA,     /*数据*/  
  28.                                     sizeof(MCAST_DATA),     /*长度*/  
  29.                                     0,  
  30.                                     (struct sockaddr*)&mcast_addr,   
  31.                                     sizeof(mcast_addr)) ;  
  32.         if( n < 0)  
  33.         {  
  34.             perror("sendto()");  
  35.             return -2;  
  36.         }         
  37.           
  38.         sleep(MCAST_INTERVAL);                          /*等待一段时间*/  
  39.     }  
  40.       
  41.     return 0;  

 

一个多播例子的客户端

多播组的IP地址为224.0.0.88,端口为8888,当客户端接收到多播的数据后将打印出来。

客户端只有在加入多播组后才能接受多播组的数据,因此多播客户端在接收多播组的数据之前需要先加入多播组,当接收完毕后要退出多播组。

  1. /*  
  2. *broadcast_client.c - 多播的客户端  
  3. */  
  4. #define MCAST_PORT 8888;  
  5. #define MCAST_ADDR "224.0.0.88"     /*一个局部连接多播地址,路由器不进行转发*/  
  6. #define MCAST_INTERVAL 5                        /*发送间隔时间*/  
  7. #define BUFF_SIZE 256                           /*接收缓冲区大小*/  
  8. int main(int argc, char*argv[])  
  9. {     
  10.     int s;                                      /*套接字文件描述符*/  
  11.     struct sockaddr_in local_addr;              /*本地地址*/  
  12.     int err = -1;  
  13.       
  14.     s = socket(AF_INET, SOCK_DGRAM, 0);     /*建立套接字*/  
  15.     if (s == -1)  
  16.     {  
  17.         perror("socket()");  
  18.         return -1;  
  19.     }     
  20.       
  21.                                                 /*初始化地址*/  
  22.     memset(&local_addr, 0, sizeof(local_addr));  
  23.     local_addr.sin_family = AF_INET;  
  24.     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
  25.     local_addr.sin_port = htons(MCAST_PORT);  
  26.       
  27.                                                 /*绑定socket*/  
  28.     err = bind(s,(struct sockaddr*)&local_addr, sizeof(local_addr)) ;  
  29.     if(err < 0)  
  30.     {  
  31.         perror("bind()");  
  32.         return -2;  
  33.     }  
  34.       
  35.                                                 /*设置回环许可*/  
  36.     int loop = 1;  
  37.     err = setsockopt(s,IPPROTO_IP, IP_MULTICAST_LOOP,&loop, sizeof(loop));  
  38.     if(err < 0)  
  39.     {  
  40.         perror("setsockopt():IP_MULTICAST_LOOP");  
  41.         return -3;  
  42.     }  
  43.       
  44.     struct ip_mreq mreq;                                    /*加入广播组*/  
  45.     mreq.imr_multiaddr.s_addr = inet_addr(MCAST_ADDR);  /*广播地址*/  
  46.     mreq.imr_interface.s_addr = htonl(INADDR_ANY);  /*网络接口为默认*/  
  47.                                                         /*将本机加入广播组*/  
  48.     err = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof   
  49.     (mreq));  
  50.     if (err < 0)  
  51.     {  
  52.         perror("setsockopt():IP_ADD_MEMBERSHIP");  
  53.         return -4;  
  54.     }  
  55.       
  56.     int times = 0;  
  57.     int addr_len = 0;  
  58.     char buff[BUFF_SIZE];  
  59.     int n = 0;  
  60.                                         /*循环接收广播组的消息,5次后退出*/  
  61.     for(times = 0;times<5;times++)  
  62.     {  
  63.         addr_len = sizeof(local_addr);  
  64.         memset(buff, 0, BUFF_SIZE);                 /*清空接收缓冲区*/  
  65.                                                     /*接收数据*/  
  66.         n = recvfrom(s, buff, BUFF_SIZE, 0,(struct sockaddr*)&local_addr,   
  67.         &addr_len);  
  68.         if( n== -1)   
  69.         {  
  70.             perror("recvfrom()");  
  71.         }  
  72.                                                     /*打印信息*/  
  73.         printf("Recv %dst message from server:%s\n", times, buff);  
  74.         sleep(MCAST_INTERVAL);   
  75.     }  
  76.       
  77.                                                     /*退出广播组*/  
  78.     err = setsockopt(s, IPPROTO_IP, IP_DROP_MEMBERSHIP,&mreq, sizeof   
  79.     (mreq));  
  80.           
  81.     close(s);  
  82.     return 0;  
修正: 
上面的做法,windows同样适用,只需改动SOCKET, closesocket少数几个地方就可以。运行结果是:如果client和server在同一台机台上运行,OK;如果在局域网不同机台上运行,client抓不到数据。
修正这个问题,需要将上面client中代码 mreq.imr_interface.s_addr = htonl(INADDR_ANY);  改为 mreq.imr_interface.s_addr = htonl(MCAST_LOCALIF);  其中MCAST_LOCALIF是自定义的本地IP地址。运行OK了,利用抓包工具也可以看到UDP数据包。

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值