51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

UDP特性之广播

  1. 广播的特点 {#1-广播的特点} ===================

广播的UDP的特性之一,通过广播可以向子网中多台计算机发送消息,并且子网中所有的计算机都可以接收到发送方发送的消息,每个广播消息都包含一个特殊的IP地址,这个IP中子网内主机标志部分的二进制全部为1 (即点分十进制IP的最后一部分是255)。点分十进制的IP地址每一部分是1字节,最大值为255,比如:192.168.1.100

  • 前两部分192.168表示当前网络是局域网
  • 第三部分1表示局域网中的某一个网段,最大值为 255
  • 第四部分100用于标记当前网段中的某一台主机,最大值为255
  • 每个网段都有一个特殊的广播地址,即:192.168.xxx.255

广播分为两端,即数据发送端和数据接收端,通过广播的方式发送数据,发送端和接收端的关系是 1:N

  • 发送广播消息的一端,通过广播地址,可以将消息同时发送到局域网的多台主机上(数据接收端)

  • 在发送广播消息的时候,必须要把数据发送到广播地址上

  • 广播只能在局域网内使用,广域网是无法使用UDP进行广播的

  • 只要发送端在发送广播消息,数据接收端就能收到广播消息,消息的接收是无法拒绝的,除非将接收端的进程关闭,就接收不到了。

UDP的广播和日常生活中的广播是一样的,都是一种快速传播消息的方式,因此广播的开销很小,发送端使用一个广播地址,就可以将数据发送到多个接收数据的终端上,如果不使用广播,就需要进行多次发送才能将数据分别发送到不同的主机上。

  1. 设置广播属性 {#2-设置广播属性} =====================

基于UDP虽然可以进行数据的广播,但是这个属性默认是关闭的,如果需要对数据进行广播,那么需要在广播端代码中开启广播属性,需要通过套接字选项函数进行设置,该函数原型为:

|-----------|----------------------------------------------------------------------------------------------------| | 1 | int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); |

  • 参数:
    • sockfd:进行UDP通信的文件描述符
    • level: 套接字级别,需要设置为 SOL_SOCKET
    • optname:选项名,此处要设置udp的广播属性,该参数需要指定为:SO_BROADCAST
    • optval:如果是设置广播属性,该指针实际指向一块int类型的内存
      • 该整型值为0:关闭广播属性
      • 该整形值为1:打开广播属性
    • optlen:optval指针指向的内存大小,即:sizeof(int)
  • 返回值:函数调用成功返回0,失败返回-1
  1. 广播通信流程 {#3-广播通信流程} =====================

如果使用UDP在局域网范围内进行消息的广播,一般情况下广播端只发送数据,接收端只接受广播消息。因此在数据接收端需要绑定固定的端口,广播端则不需要手动绑定固定端口,自动随机绑定即可。

  • 数据发送端

    1. 创建通信的套接字

      |-------------|--------------------------------------------------------------------------------------------| | 1 2 | // 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp int fd = socket(AF_INET, SOCK_DGRAM, 0); |

    2. 主动发送数据不需要手动绑定固定端口(自动随机分配就可以了),因此直接设置广播属性

      |-------------|------------------------------------------------------------------------------------| | 1 2 | int opt = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); |

    3. 使用广播地址发送广播数据到接收端绑定的固定端口上

      |-----------|-------------------| | 1 | sendto(); |

    4. 关闭套接字(文件描述符)

      |-----------|--------------------| | 1 | close(fd); |

  • 数据接收端

    1. 创建通信的套接字

      |-------------|--------------------------------------------------------------------------------------------| | 1 2 | // 第二个参数是 SOCK_DGRAM, 第三个参数0表示使用报式协议中的udp int fd = socket(AF_INET, SOCK_DGRAM, 0); |

    2. 因为是被动接收数据的一端,所以必须要绑定固定的端口和本地IP地址

      |-----------|-----------------| | 1 | bind(); |

    3. 接收广播消息

      |-----------|---------------------| | 1 | recvfrom(); |

    4. 关闭套接字(文件描述符)

      |-----------|--------------------| | 1 | close(fd); |

  1. 通信代码 {#4-通信代码} =================

广播端

|------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> int main() { // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); } // 2. 设置广播属性 int opt = 1; setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)); char buf[1024]; struct sockaddr_in cliaddr; int len = sizeof(cliaddr); cliaddr.sin_family = AF_INET; cliaddr.sin_port = htons(9999); // 接收端需要绑定9999端口 // 只要主机在237网段, 并且绑定了9999端口, 这个接收端就能收到广播消息 inet_pton(AF_INET, "192.168.237.255", &cliaddr.sin_addr.s_addr); // 3. 通信 int num = 0; while(1) { sprintf(buf, "hello, client...%d\n", num++); // 数据广播 sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&cliaddr, len); printf("发送的广播的数据: %s\n", buf); sleep(1); } close(fd); return 0; } |

注意事项:发送广播消息一端必须要开启UDP的广播属性,并且发送消息的地址必须是当前发送端所在网段的广播地址,这样才能通过调用一个消息发送函数将消息同时发送N台接收端主机上。

接收端

|---------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> int main() { // 1. 创建通信的套接字 int fd = socket(AF_INET, SOCK_DGRAM, 0); if(fd == -1) { perror("socket"); exit(0); } // 2. 通信的套接字和本地的IP与端口绑定 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(9999); // 大端 addr.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0 int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); if(ret == -1) { perror("bind"); exit(0); } char buf[1024]; // 3. 通信 while(1) { // 接收广播消息 memset(buf, 0, sizeof(buf)); // 阻塞等待数据达到 recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL); printf("接收到的广播消息: %s\n", buf); } close(fd); return 0; } |

对于接收广播消息的一端,必须要绑定固定的端口,并由广播端将广播消息发送到这个端口上,因此所有接收端都应绑定相同的端口,这样才能同时收到广播数据。

赞(0)
未经允许不得转载:工具盒子 » UDP特性之广播