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、套接字选项

cpp 复制代码
#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 发送者

cpp 复制代码
//广播发送者代码实现
#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 接收者

cpp 复制代码
#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;
}

执行结果

相关推荐
久绊A35 分钟前
网络信息系统的整个生命周期
网络
_PowerShell41 分钟前
[ DOS 命令基础 3 ] DOS 命令详解-文件操作相关命令
网络·dos命令入门到精通·dos命令基础·dos命令之文件操作命令详解·文件复制命令详解·文件对比命令详解·文件删除命令详解·文件查找命令详解
龙鸣丿41 分钟前
Linux基础学习笔记
linux·笔记·学习
耶啵奶膘2 小时前
uniapp-是否删除
linux·前端·uni-app
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
_.Switch3 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
2401_850410833 小时前
文件系统和日志管理
linux·运维·服务器
qq_254674413 小时前
工作流初始错误 泛微提交流程提示_泛微协同办公平台E-cology8.0版本后台维护手册(11)–系统参数设置
网络
JokerSZ.3 小时前
【基于LSM的ELF文件安全模块设计】参考
运维·网络·安全
XMYX-04 小时前
使用 SSH 蜜罐提升安全性和记录攻击活动
linux·ssh