socket udp广播和多播的简单实现

UDP广播与多播

作者:legend

QQ:1327706646

使用UDP协议进行信息的传输之前不需要建议连接。换句话说就是客户端向服务器发送信息,客户端只需要给出服务器的ip地址和端口号,然后将信息封装到一个待发送的报文中并且发送出去。至于服务器端是否存在,或者能否收到该报文,客户端根本不用管。

通常我们讨论的udp的程序都是一对一的单播程序。本章将讨论一对多的服务:广播(broadcast)、多播(multicast)。对于广播,网络中的所有主机都会接收一份数据副本。对于多播,消息只是发送到一个多播地址,网络知识将数据分发给哪些表示想要接收发送到该多播地址的数据的主机。总得来说,只有UDP套接字允许广播或多播。

UDP广播

广播UDP与单播UDP的区别就是IP地址不同,广播使用广播地址255.255.255.255,将消息发送到在同一广播网络上的每个主机。值得强调的是:本地广播信息是不会被路由器转发。当然这是十分容易理解的,因为如果路由器转发了广播信息,那么势必会引起网络瘫痪。这也是为什么IP协议的设计者故意没有定义互联网范围的广播机制。

广播地址通常用于在网络游戏中处于同一本地网络的玩家之间交流状态信息等。广播就不在写演示程序了,读者可以将ECHO程序的ip地址改为广播地址即可。

其实广播顾名思义,就是想局域网内所有的人说话,但是广播还是要指明接收者的端口号的,因为不可能接受者的所有端口都来收听广播。

UDP多播

  1. 同样的UDP多播也要指明接受者的端口号,而且与广播相似的是多播与单播之间的区别还在于地址。ipv4中的多播地址范围是:224.0.0.0到239.255.255.255。在JAVA中,多播一样十分好实现,要实现多播,就要用到MulticastSocket类,其实该类就是DatagramSocket的子类,在使用时除了多播自己的一些特性外,把它当做DatagramSocket类使用就可以了。下面将给出一个简单的多播接受数据的例子:
    1. // 发送端   
    2. #include <iostream>   
    3. #include <stdio.h>   
    4. #include <sys/socket.h>   
    5. #include <unistd.h>   
    6. #include <sys/types.h>   
    7. #include <netdb.h>   
    8. #include <netinet/in.h>   
    9. #include <arpa/inet.h>   
    10. #include <string.h>   
    11.   
    12.   
    13. using namespace std;  
    14.   
    15. int main()  
    16. {  
    17.     setvbuf(stdout, NULL, _IONBF, 0);   
    18.     fflush(stdout);   
    19.   
    20.     int sock = -1;  
    21.     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
    22.     {     
    23.         cout<<"socket error"<<endl;   
    24.         return false;  
    25.     }     
    26.       
    27.     const int opt = 1;  
    28.     //设置该套接字为广播类型,   
    29.     int nb = 0;  
    30.     nb = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
    31.     if(nb == -1)  
    32.     {  
    33.         cout<<"set socket error..."<<endl;  
    34.         return false;  
    35.     }  
    36.   
    37.     struct sockaddr_in addrto;  
    38.     bzero(&addrto, sizeof(struct sockaddr_in));  
    39.     addrto.sin_family=AF_INET;  
    40.     addrto.sin_addr.s_addr=htonl(INADDR_BROADCAST);  
    41.     addrto.sin_port=htons(6000);  
    42.     int nlen=sizeof(addrto);  
    43.   
    44.     while(1)  
    45.     {  
    46.         sleep(1);  
    47.         //从广播地址发送消息   
    48.         char smsg[] = {"abcdef"};  
    49.         int ret=sendto(sock, smsg, strlen(smsg), 0, (sockaddr*)&addrto, nlen);  
    50.         if(ret<0)  
    51.         {  
    52.             cout<<"send error...."<<ret<<endl;  
    53.         }  
    54.         else  
    55.         {         
    56.             printf("ok ");    
    57.         }  
    58.     }  
    59.   
    60.     return 0;  
    61. }  
    1. // 接收端 http://blog.csdn.net/robertkun   
    2.   
    3. #include <iostream>   
    4. #include <stdio.h>   
    5. #include <sys/socket.h>   
    6. #include <unistd.h>   
    7. #include <sys/types.h>   
    8. #include <netdb.h>   
    9. #include <netinet/in.h>   
    10. #include <arpa/inet.h>   
    11. #include <string.h>   
    12.   
    13.   
    14. using namespace std;  
    15.   
    16. int main()  
    17. {  
    18.     setvbuf(stdout, NULL, _IONBF, 0);   
    19.     fflush(stdout);   
    20.   
    21.     // 绑定地址   
    22.     struct sockaddr_in addrto;  
    23.     bzero(&addrto, sizeof(struct sockaddr_in));  
    24.     addrto.sin_family = AF_INET;  
    25.     addrto.sin_addr.s_addr = htonl(INADDR_ANY);  
    26.     addrto.sin_port = htons(6000);  
    27.       
    28.     // 广播地址   
    29.     struct sockaddr_in from;  
    30.     bzero(&from, sizeof(struct sockaddr_in));  
    31.     from.sin_family = AF_INET;  
    32.     from.sin_addr.s_addr = htonl(INADDR_ANY);  
    33.     from.sin_port = htons(6000);  
    34.       
    35.     int sock = -1;  
    36.     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
    37.     {     
    38.         cout<<"socket error"<<endl;   
    39.         return false;  
    40.     }     
    41.   
    42.     const int opt = 1;  
    43.     //设置该套接字为广播类型,   
    44.     int nb = 0;  
    45.     nb = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
    46.     if(nb == -1)  
    47.     {  
    48.         cout<<"set socket error..."<<endl;  
    49.         return false;  
    50.     }  
    51.   
    52.     if(bind(sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1)   
    53.     {     
    54.         cout<<"bind error..."<<endl;  
    55.         return false;  
    56.     }  
    57.   
    58.     int len = sizeof(sockaddr_in);  
    59.     char smsg[100] = {0};  
    60.   
    61.     while(1)  
    62.     {  
    63.         //从广播地址接受消息   
    64.         int ret=recvfrom(sock, smsg, 100, 0, (struct sockaddr*)&from,(socklen_t*)&len);  
    65.         if(ret<=0)  
    66.         {  
    67.             cout<<"read error...."<<sock<<endl;  
    68.         }  
    69.         else  
    70.         {         
    71.             printf("%s ", smsg);     
    72.         }  
    73.   
    74.         sleep(1);  
    75.     }  
    76.   
    77.     return 0;  
    78. }  
  2. 自已在Linux虚拟机下测试可以成功, 前提是要把主机设置在同一网段内, 还有就是不要忘记关闭Linux的防火墙.. 可以使用setup命令进行设置。

    (我在测试的时候只能发送不收接收,折磨了我半天,后来才想到是Linux防火墙的问题。。)

    关于虚拟机的网卡配置,建议选择桥接模式。NAT的模式的话,是受限制的,可能会收不到广播消息。

    具体的参考网上的文章吧。。

原文地址:https://www.cnblogs.com/pengkunfan/p/3585540.html