UDP广播

1、UDP广播

1.1、广播的概念

广播:由一台主机向该主机所在子网内的所有主机发送数据的方式

例如 :192.168.3.103主机发送广播信息,则192.168.3.1~192.168.3.254所有主机都可以接收到数据

广播只能用UDP或原始IP实现,不能用TCP

1.2、广播的用途

单个服务器与多个客户主机通信时减少分组流通 以下几个协议都用到广播

1、地址解析协议(ARP)

2、动态主机配置协议(DHCP)

3、网络时间协议(NTP)

1.3、广播的特点

  1. 同一子网内的所有主机都必须处理接收到的数据。这意味着当一台主机发送广播信息时,子网内的所有其他主机都将接收并处理该数据,无论它们是否需要该信息。
  2. 由于广播只能通过UDP或原始IP实现,因此UDP数据包会沿着协议栈向上传输,直到到达UDP层。这与TCP不同,TCP数据包在传输过程中会经过更多的协议层处理。
  3. 运行音频、视频等高速率应用时,广播通信可能会带来较大的负载。这是因为所有主机都必须处理接收到的数据,即使它们并不需要这些数据。这可能会导致网络拥塞和性能下降。
  4. 广播通信通常局限于局域网(LAN)内使用。这是因为广播信息会被发送到子网内的所有主机,而不同子网之间的通信通常需要使用其他网络协议,如单播或多播。

1.4、广播地址

{网络ID,主机ID}

网络ID表示由子网掩码中1覆盖的连续位

主机ID表示由子网掩码中0覆盖的连续位

定向广播地址:主机ID全1

1、例:对于192.168.220.0/24,其定向广播地址为192.168.220.255 2、通常路由器不转发该广播

受限广播地址:255.255.255.255

路由器从不转发该广播

2 、广播与单播的对比

单播

 广播

3 、广播流程 

  1. 创建套接字:使用socket()函数创建一个数据报套接字(SOCK_DGRAM),以支持UDP通信。
  2. 设置广播权限:使用setsockopt()函数将套接字设置为允许发送广播数据。这通常需要设置SO_BROADCAST选项。
  3. 发送数据:使用sendto()函数向广播地址发送数据。广播地址是一个特殊的IP地址,用于表示子网内的所有主机。例如,在IPv4中,广播地址通常表示为子网掩码全1的形式。

接收广播数据的步骤如下:

  1. 创建套接字:与发送者一样,使用socket()函数创建一个数据报套接字(SOCK_DGRAM)。
  2. 绑定套接字:使用bind()函数将套接字与一个本地地址和端口号绑定。这将使套接字能够接收发送到该地址和端口的数据。
  3. 接收数据:使用recvfrom()函数接收发送到绑定地址和端口的数据。该函数将返回发送者的信息,包括其IP地址和端口号。

4、套接字选项 

#include <sys/socket.h>

int setsockopt(int socket, int level, int option_name,
               const void *option_value, socklen_t option_len);

功能:设置一个套接字的选项(属性)

参数:
    socket:文件描述符
    level:协议层次
      SOL_SOCKET 套接字层次
      IPPROTO_TCP tcp层次
      IPPROTO_IP IP层次
    option_name:选项的名称
      SO_BROADCAST 允许发送广播数据(SOL_SOCKET层次的)
    option_value:设置的选项的值
    int类型的值,存储的是bool的数据(1和0)
      0 不允许
      1 允许
option_len:option_value的长度

返回值:
    成功:0
    失败:-1

 5、广播示例 

5.1 发送者

//广播发送者代码实现
#include <stdio.h> //printf
#include <stdlib.h> //exit
#include <sys/types.h>
#include <sys/socket.h> //socket
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h> //htons inet_addr
#include <unistd.h> //close
#include <string.h>

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd; //文件描述符
    struct sockaddr_in broadcataddr; //服务器网络信息结构体
    socklen_t addrlen = sizeof(broadcataddr);

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("fail to socket");
        exit(1);
    }

    //第二步:设置为允许发送广播权限
    int on = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0)
    {
        perror("fail to setsockopt");
        exit(1);
    }

    //第三步:填充广播信息结构体
    broadcataddr.sin_family = AF_INET;
    broadcataddr.sin_addr.s_addr = inet_addr(argv[1]); //192.168.3.255 255.255.255.255
    broadcataddr.sin_port = htons(atoi(argv[2]));

    //第四步:进行通信
    char buf[128] = "";
    while(1)
    {
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf) - 1] = '\0';

        if(sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&broadcataddr, addrlen) < 0)
        {
            perror("fail to sendto");
            exit(1);
        }
    }

    return 0;
}

5.2 接收者

#include <stdio.h> //printf
#include <stdlib.h> //exit
#include <sys/types.h>
#include <sys/socket.h> //socket
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h> //htons inet_addr
#include <unistd.h> //close
#include <string.h>

int main(int argc, char const *argv[])
{
    if(argc < 3)
    {
        fprintf(stderr, "Usage: %s <ip> <port>\n", argv[0]);
        exit(1);
    }

    int sockfd; //文件描述符
    struct sockaddr_in broadcataddr; 
    socklen_t addrlen = sizeof(broadcataddr);

    //第一步:创建套接字
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("fail to socket");
        exit(1);
    }

    //第二步:填充广播信息结构体
    broadcataddr.sin_family = AF_INET;
    broadcataddr.sin_addr.s_addr = inet_addr(argv[1]); //192.168.3.255 255.255.255.255
    broadcataddr.sin_port = htons(atoi(argv[2]));

    //第三步:将套接字与广播信息结构体绑定
    if(bind(sockfd, (struct sockaddr *)&broadcataddr, addrlen) < 0)
    {
        perror("fail to bind");
        exit(1);
    }

    //第四步:进行通信
    char text[32] = "";
    struct sockaddr_in sendaddr;

    while(1)
    {
        if(recvfrom(sockfd, text, sizeof(text), 0, (struct sockaddr *)&sendaddr, &addrlen) < 0)
        {
            perror("fail to recvfrom");
            exit(1);
        }
        
        printf("[%s - %d]: %s\n", inet_ntoa(sendaddr.sin_addr), ntohs(sendaddr.sin_port), text);
    }

    return 0;
}

执行结果

相关推荐

  1. <span style='color:red;'>UDP</span><span style='color:red;'>广播</span>

    UDP广播

    2024-05-10 16:58:05      16 阅读
  2. devc++ 使用 winsock 实现 UDP 广播

    2024-05-10 16:58:05       34 阅读
  3. android开发:获取手机IP和UDP广播

    2024-05-10 16:58:05       36 阅读
  4. QT网络编程之实现UDP广播发送和接收

    2024-05-10 16:58:05       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-10 16:58:05       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-10 16:58:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-10 16:58:05       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-10 16:58:05       20 阅读

热门阅读

  1. 力扣 673. 最长递增子序列的个数 python AC

    2024-05-10 16:58:05       13 阅读
  2. 深入理解Spring中的@Autowired注解

    2024-05-10 16:58:05       10 阅读
  3. Android Blueprint简介

    2024-05-10 16:58:05       15 阅读
  4. Nanopc T4 使用OpenCV

    2024-05-10 16:58:05       12 阅读
  5. RabbitMQ

    RabbitMQ

    2024-05-10 16:58:05      12 阅读
  6. OceanBase 中的ROWID与Oracle的差异与如何迁移

    2024-05-10 16:58:05       15 阅读
  7. 面试前的刷题,要有充分的准备

    2024-05-10 16:58:05       9 阅读