欢迎光临
我们一直在努力

Linux网络编程:UDP组播与广播深度详解

前言

在Linux网络编程中,UDP协议提供了三种通信模式:单播(Unicast)、广播(Broadcast) 和 组播(Multicast)。本文将深入剖析广播与组播的编程模型,从核心接口到每一行代码的注释分析,帮助读者彻底掌握这两种一对多通信方式。

本文分为三部分:

  • UDP基础与核心接口详解

  • 广播编程实战

  • 组播编程实战


  • 第一部分:UDP基础与核心接口详解

    1.1 UDP协议概述

    UDP(User Datagram Protocol,用户数据报协议)是一种面向无连接的传输层协议。与TCP不同,UDP在传输数据前不需要建立连接,可以直接通信。

    UDP核心特点

    特性说明
    无连接 发送数据前不需要建立连接
    不可靠 不保证到达、不保证顺序、不保证不重复
    速度快 无握手、无确认、无重传
    面向报文 保留消息边界,一次发送对应一次接收
    支持广播/组播 可向多个目标同时发送数据

    UDP与TCP对比

    对比维度TCPUDP
    连接方式 面向连接(三次握手) 无连接
    可靠性 可靠(确认、重传、排序) 不可靠
    传输速度 较慢 较快
    数据边界 字节流,无边界 数据报,有边界
    首部开销 20字节(最小) 8字节
    流量控制 有(滑动窗口)
    拥塞控制
    通信模式 仅一对一 一对一、一对多、多对多

    1.2 核心接口详解

    接口一:recvfrom —— 接收数据

    c

    #include <sys/types.h>
    #include <sys/socket.h>

    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
    struct sockaddr *src_addr, socklen_t *addrlen);

    功能:从套接字接收数据,并获取发送方的地址信息。

    参数详解:

    参数类型作用
    sockfd int 套接字描述符
    buf void* 接收数据的缓冲区
    len size_t 缓冲区长度
    flags int 标志位(0阻塞,MSG_DONTWAIT非阻塞)
    src_addr struct sockaddr* 输出参数,保存发送方地址
    addrlen socklen_t* 输入输出参数,传入src_addr长度,返回实际长度

    flags 参数:0 与 MSG_DONTWAIT 的区别

    一、核心区别

    对比项0(阻塞)MSG_DONTWAIT(非阻塞)
    有数据时 立即返回 立即返回
    无数据时 一直等待(卡住) 立即返回 -1
    errno 不设置 EAGAIN 或 EWOULDBLOCK
    CPU占用 高(需轮询)

    二、一句话理解

    • 0:没有数据就等,直到有数据才继续(程序卡住)

    • MSG_DONTWAIT:没有数据就立即返回,不等待(程序不卡)

    三、典型代码

    阻塞:

    recvfrom(sockfd, buf, len, 0, NULL, NULL); // 没数据就卡住

    非阻塞:

    int ret = recvfrom(sockfd, buf, len, MSG_DONTWAIT, NULL, NULL);
    if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
    // 没数据,不是错误,继续做别的事
    }

    四、注意点

  • MSG_DONTWAIT 只影响本次调用,下次调用如果 flags=0 又会阻塞。

  • 要永久非阻塞,用 fcntl 设置 O_NONBLOCK。

  • EAGAIN 和 EWOULDBLOCK 在 Linux 中值相同,都表示"暂时无数据"。

  • 五、选择建议

    场景推荐
    单连接、简单程序 0(阻塞)
    高并发、多连接 epoll + fcntl 永久非阻塞
    临时试一下 MSG_DONTWAIT

    一句话:0 是"没数据就等",MSG_DONTWAIT 是"没数据就走"。

    返回值:成功返回接收的字节数,失败返回-1。

    接口二:sendto —— 发送数据

    #include <sys/types.h>
    #include <sys/socket.h>

    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
    const struct sockaddr *dest_addr, socklen_t addrlen);

    功能:向指定地址发送数据。

    参数详解:

    参数类型作用
    sockfd int 套接字描述符
    buf const void* 要发送的数据
    len size_t 数据长度
    flags int 标志位
    dest_addr const struct sockaddr* 目标网络地址
    addrlen socklen_t 目标地址长度

    返回值:成功返回发送的字节数,失败返回-1。

    接口三:setsockopt —— 设置套接字选项

    #include <sys/socket.h>

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

    功能:设置套接字的选项,控制套接字行为。

    参数详解:

    参数类型作用
    sockfd int 套接字描述符
    level int 选项所在协议层(SOL_SOCKET、IPPROTO_IP等)
    optname int 具体选项名
    optval const void* 选项值的指针
    optlen socklen_t 选项值的长度

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

    常用选项:

    选项名作用适用场景
    SO_BROADCAST 允许发送广播 UDP广播发送方
    SO_REUSEADDR 允许地址复用 服务器重启
    SO_SNDBUF 设置发送缓冲区大小 性能调优
    SO_RCVBUF 设置接收缓冲区大小 性能调优
    IP_ADD_MEMBERSHIP 加入组播组 UDP组播接收方
    IP_DROP_MEMBERSHIP 离开组播组 UDP组播接收方

    第二部分:广播编程实战

    2.1 广播的概念

    UDP广播是指向同一子网内所有主机发送数据。广播地址使用255.255.255.255(受限广播)或定向广播地址(如192.168.1.255)。

    广播地址类型

    类型地址是否被路由转发作用范围
    受限广播 255.255.255.255 不转发 仅本子网
    定向广播 如192.168.1.255 可转发(需配置) 指定子网

    关键点:为什么发送方不需要bind?

    角色是否bind原因
    发送方 不需要 只是"喊话",不需要别人找到它
    接收方 必须 要被广播包"送达",必须占固定端口

    类比:村支书用大喇叭喊话(发送方不需要告诉别人自己在哪),村民必须待在固定频率收听(接收方必须占坑)。

    2.2 广播发送方代码详解

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <stdlib.h>

    int main(void)
    {
    // 1. 创建UDP套接字
    // AF_INET: IPv4协议族
    // SOCK_DGRAM: 数据报套接字,对应UDP协议
    // 0: 使用默认协议(UDP)
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    // 检查套接字创建是否成功
    if (sockfd == -1) {
    perror("socket failed."); // 打印错误信息
    exit(1); // 异常退出
    }

    // 2. 设置广播属性(关键步骤!)
    // opt = 1 表示开启广播发送权限
    // opt = 0 表示关闭广播发送权限
    int opt = 1;

    // setsockopt参数详解:
    // 参数1 sockfd: 要设置的套接字
    // 参数2 SOL_SOCKET: 通用套接字选项层
    // 参数3 SO_BROADCAST: 开启广播发送权限
    // 参数4 &opt: 指向选项值的指针
    // 参数5 sizeof(opt): 选项值长度
    setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));

    // 3. 设置广播目标地址
    struct sockaddr_in senderAddr;
    senderAddr.sin_family = AF_INET; // 地址族:IPv4
    senderAddr.sin_port = htons(9999); // 端口:9999(网络字节序)
    senderAddr.sin_addr.s_addr = inet_addr("255.255.255.255"); // 受限广播地址

    // 4. 准备发送的数据
    char buff[BUFSIZ] = "大家好!新年快乐!"; // BUFSIZ是系统定义的缓冲区大小

    // 5. 发送广播数据
    // sendto参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 buff: 要发送的数据
    // 参数3 strlen(buff)+1: 数据长度(+1包含结束符'\\0')
    // 参数4 0: 标志位,0表示阻塞发送
    // 参数5 (struct sockaddr*)&senderAddr: 目标地址
    // 参数6 sizeof(senderAddr): 地址长度
    int ret = sendto(sockfd, buff, strlen(buff) + 1, 0,
    (struct sockaddr*)&senderAddr, sizeof(senderAddr));

    // 检查发送是否成功
    if (ret < 0) {
    perror("sendto failed.");
    } else {
    printf("已发送广播 %d 字节: %s\\n", ret, buff);
    }

    // 6. 关闭套接字
    close(sockfd);

    return 0;
    }

    代码逐行分析

    代码行作用
    socket(AF_INET, SOCK_DGRAM, 0) 创建UDP套接字
    int opt = 1; 定义选项变量,1表示开启
    setsockopt(…, SO_BROADCAST, &opt, sizeof(opt)) 开启广播权限
    senderAddr.sin_addr.s_addr = inet_addr("255.255.255.255") 设置广播目标地址
    sendto(…) 发送广播数据包
    close(sockfd) 关闭套接字释放资源

    2.3 广播接收方代码详解

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <stdlib.h>

    int main(void)
    {
    // 1. 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (sockfd == -1) {
    perror("socket failed.");
    exit(1);
    }

    // 2. 设置接收地址
    struct sockaddr_in receiverAddr;
    receiverAddr.sin_family = AF_INET; // IPv4协议族
    receiverAddr.sin_port = htons(9999); // 端口:9999(必须和发送方一致)

    // INADDR_ANY = 0.0.0.0,表示绑定本机所有网卡
    // 这是接收广播的正确方式,能收到所有网卡上的广播包
    receiverAddr.sin_addr.s_addr = INADDR_ANY;

    // 保存地址长度
    socklen_t len = sizeof(receiverAddr);

    // 3. 绑定地址(接收方必须bind)
    // bind参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 (struct sockaddr*)&receiverAddr: 本地地址
    // 参数3 sizeof(receiverAddr): 地址长度
    int ret = bind(sockfd, (struct sockaddr*)&receiverAddr, sizeof(receiverAddr));

    if (ret == -1) {
    perror("bind failed.");
    exit(1);
    }

    // 4. 接收广播数据
    char buff[BUFSIZ];

    // recvfrom参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 buff: 接收缓冲区
    // 参数3 sizeof(buff): 缓冲区大小
    // 参数4 0: 标志位,0表示阻塞接收
    // 参数5 (struct sockaddr*)&receiverAddr: 发送方地址(输出参数)
    // 参数6 &len: 地址长度(输入输出参数)
    ret = recvfrom(sockfd, buff, sizeof(buff), 0,
    (struct sockaddr*)&receiverAddr, &len);

    if (ret < 0) {
    perror("recvfrom failed.");
    exit(1);
    }

    // 5. 打印收到的数据
    // inet_ntop: 将网络地址转换为字符串
    char ipaddr[64];
    inet_ntop(AF_INET, &receiverAddr.sin_addr, ipaddr, sizeof(ipaddr));

    printf("收到来自 %s 的 %d 字节: %s\\n", ipaddr, ret, buff);

    // 6. 关闭套接字
    close(sockfd);

    return 0;
    }

    代码逐行分析

    代码行作用
    socket(AF_INET, SOCK_DGRAM, 0) 创建UDP套接字
    receiverAddr.sin_port = htons(9999) 设置监听端口,必须和发送方一致
    receiverAddr.sin_addr.s_addr = INADDR_ANY 绑定所有网卡,接收广播
    bind(sockfd, …) 绑定地址到套接字
    recvfrom(sockfd, …) 阻塞接收广播数据
    inet_ntop(…) 将二进制IP转换为字符串
    close(sockfd) 关闭套接字

    2.4 INADDR_ANY深入解析

    #define INADDR_ANY ((in_addr_t) 0x00000000) // 即 0.0.0.0

    INADDR_ANY的真实含义:绑定到本机所有网卡上的所有IP地址。

    绑定方式含义能否收外部广播
    INADDR_ANY 所有网卡 ✅ 能
    127.0.0.1 仅回环网卡 ❌ 不能
    192.168.1.169 仅指定网卡 ⚠️ 部分能

    实验验证:

    接收方绑定能否收到192.168.1.168发来的广播
    INADDR_ANY ✅ 能收到
    127.0.0.1 ❌ 收不到
    192.168.1.169 ✅ 能收到(但仅限该网卡)

    第三部分:组播编程实战

    3.1 组播的概念

    组播(多播)是向一组特定主机发送数据,介于单播和广播之间,能有效节省网络带宽。

    组播的核心机制:订阅制

    组播的本质是"订阅制":

    • 只有主动加入组播组的主机,才能收到发往该组播地址的数据

    • 未加入组的主机,根本收不到数据

    组播地址范围

    类型地址范围说明
    局部链接多播 224.0.0.0 ~ 224.0.0.255 路由协议保留,不转发
    预留多播 224.0.1.0 ~ 238.255.255.255 用户可用,可用于Internet
    管理权限多播 239.0.0.0 ~ 239.255.255.255 组织内部使用,类似私有IP

    224.0.0.88属于局部链接多播地址,仅本子网有效,路由器不转发。

    广播 vs 组播对比

    对比项广播组播
    目标地址 255.255.255.255 224.0.0.88
    网络设备处理 无差别转发给所有主机 只转发给加入组的主机
    接收方要求 只需bind bind + IP_ADD_MEMBERSHIP
    订阅制
    网络开销

    类比:

    • 广播 = 村里大喇叭(全村人都能听到)

    • 组播 = 微信群(只有群成员能收到)

    3.2 组播发送方代码详解

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>

    int main(void)
    {
    char buf[BUFSIZ];

    // 1. 创建UDP套接字
    // 注意:组播发送方不需要设置SO_BROADCAST
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (-1 == sockfd) {
    perror("socket");
    exit(1);
    }

    // 2. 设置组播目标地址
    struct sockaddr_in peer;
    peer.sin_family = AF_INET; // IPv4协议族
    peer.sin_port = htons(9000); // 目标端口:9000
    peer.sin_addr.s_addr = inet_addr("224.0.0.88"); // 组播地址(D类地址)

    printf("准备发送组播数据…\\n");

    // 3. 循环向组播组发送数据
    for (int i = 1; ; i++) {
    // 格式化消息内容
    sprintf(buf, "新年好, 第 %d 次问候!", i);

    // 发送组播数据
    // sendto参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 buf: 要发送的数据
    // 参数3 strlen(buf): 数据长度
    // 参数4 0: 标志位
    // 参数5 (struct sockaddr*)&peer: 组播目标地址
    // 参数6 sizeof(peer): 地址长度
    int ret = sendto(sockfd, buf, strlen(buf), 0,
    (struct sockaddr*)&peer, sizeof(peer));

    printf("已发送 %d 字节\\n", ret);

    sleep(1); // 每秒发送一次
    }

    return 0;
    }

    代码逐行分析

    代码行作用
    socket(AF_INET, SOCK_DGRAM, 0) 创建UDP套接字
    peer.sin_port = htons(9000) 设置目标端口
    peer.sin_addr.s_addr = inet_addr("224.0.0.88") 关键:设置组播地址
    sendto(…) 向组播地址发送数据
    sleep(1) 每秒发送一次

    关键点

  • 发送方不需要bind:和广播一样,发送方只是"喊话"

  • 不需要SO_BROADCAST:组播不是广播

  • 目标地址是组播地址:224.0.0.88

  • 3.3 组播接收方代码详解

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>

    int main(void)
    {
    char buf[BUFSIZ];

    // 1. 创建UDP套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (-1 == sockfd) {
    perror("socket");
    exit(1);
    }

    // 2. 绑定地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET; // IPv4协议族
    addr.sin_port = htons(9000); // 端口:9000(和发送方一致)
    addr.sin_addr.s_addr = INADDR_ANY; // 绑定所有网卡

    int ret = bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));

    if (-1 == ret) {
    perror("bind");
    exit(1);
    }

    // 3. ★ 加入组播组(关键步骤!)
    // 定义组播请求结构体
    struct ip_mreq req;

    // 设置组播地址
    req.imr_multiaddr.s_addr = inet_addr("224.0.0.88");

    // 设置本地接口,INADDR_ANY表示任意网卡
    req.imr_interface.s_addr = INADDR_ANY;

    // setsockopt参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 IPPROTO_IP: IP层选项
    // 参数3 IP_ADD_MEMBERSHIP: 加入组播组
    // 参数4 &req: 组播请求结构体
    // 参数5 sizeof(req): 结构体长度
    ret = setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
    &req, sizeof(req));

    if (ret < 0) {
    perror("setsockopt");
    exit(1);
    }

    // 4. 循环接收组播数据
    while (1) {
    // recvfrom参数详解:
    // 参数1 sockfd: 套接字
    // 参数2 buf: 接收缓冲区
    // 参数3 sizeof(buf): 缓冲区大小
    // 参数4 0: 标志位
    // 参数5 NULL: 不关心发送方地址
    // 参数6 NULL: 不关心地址长度
    ret = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);

    if (ret < 0) {
    perror("recvfrom");
    continue;
    }

    printf("收到组播数据: %s\\n", buf);
    }

    close(sockfd);
    return 0;
    }

    代码逐行分析

    代码行作用
    socket(AF_INET, SOCK_DGRAM, 0) 创建UDP套接字
    addr.sin_port = htons(9000) 设置监听端口
    addr.sin_addr.s_addr = INADDR_ANY 绑定所有网卡
    bind(sockfd, …) 绑定地址
    req.imr_multiaddr.s_addr = inet_addr("224.0.0.88") 设置组播地址
    req.imr_interface.s_addr = INADDR_ANY 设置本地接口
    setsockopt(…, IP_ADD_MEMBERSHIP, …) 关键:加入组播组
    recvfrom(…) 接收组播数据

    3.4 组播核心机制解析

    为什么必须加入组播组?

    组播的工作机制依赖于IGMP协议(Internet Group Management Protocol):

  • 主机调用setsockopt(IP_ADD_MEMBERSHIP)时

  • 内核发送IGMP Report报文给交换机/路由器

  • 网络设备记录订阅关系

  • 之后发往该组播地址的包才会转发到这台主机

  • 如果没加入组:

    • 交换机/路由器根本不会把组播包转发给你

    • recvfrom自然读不到数据

    INADDR_ANY能否替代加入组?

    ❌ 不能。

    • INADDR_ANY只是让套接字绑定到所有网卡

    • 它不告诉网络设备"我要加入某个组播组"

    • 发往224.0.0.88的包根本不会转发到你的网卡

    类比:

    • bind(INADDR_ANY) = "我把所有网卡的门都开着"

    • IP_ADD_MEMBERSHIP = "我要订阅224.0.0.88这个频道"

    • 只开门不订阅,是收不到组播频道的

    IP_ADD_MEMBERSHIP vs IP_DROP_MEMBERSHIP

    选项作用
    IP_ADD_MEMBERSHIP 加入组播组,开始接收组播数据
    IP_DROP_MEMBERSHIP 离开组播组,停止接收组播数据

    离开组播组示例:

    // 离开组播组
    setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &req, sizeof(req));

    3.5 组播通信完整流程

    text

    发送方 接收方
    | |
    socket() socket()
    | |
    | bind()
    | |
    | setsockopt(IP_ADD_MEMBERSHIP)
    | |
    sendto(224.0.0.88:9000) —-组播数据—-> recvfrom()
    | |
    | 处理数据
    | |
    close() close()

    关键点:

  • 发送方:socket() → sendto() → close()

  • 接收方:socket() → bind() → IP_ADD_MEMBERSHIP → recvfrom() → close()

  • 接收方必须加入组播组,否则收不到数据

  • 4.完整实例:UDP 回声服务器

    服务器端 server.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <stdlib.h>

    int main(void)
    {
    char buff[BUFSIZ];

    // 1. 创建 UDP 套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
    perror("socket failed.");
    exit(1);
    }

    // 2. 设置服务器地址
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(9999);
    serveraddr.sin_addr.s_addr = INADDR_ANY; // 接受任意网卡的数据

    // 3. 绑定地址
    int ret = bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    if (ret == -1) {
    perror("bind failed.");
    exit(1);
    }

    // 4. 循环接收并回复
    while (1) {
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);

    // 接收客户端数据
    int n = recvfrom(sockfd, buff, sizeof(buff), 0,
    (struct sockaddr*)&clientaddr, &len);
    if (n < 0) {
    perror("recvfrom failed.");
    continue;
    }

    printf("收到来自 %s:%d 的数据: %s\\n",
    inet_ntoa(clientaddr.sin_addr),
    ntohs(clientaddr.sin_port), buff);

    // 回复客户端
    sendto(sockfd, buff, n + 1, 0,
    (struct sockaddr*)&clientaddr, len);
    }

    close(sockfd);
    return 0;
    }

    代码解析:

    • socket(AF_INET, SOCK_DGRAM, 0):创建 UDP 套接字,SOCK_DGRAM 表示数据报服务

    • bind():将套接字与端口 9999 绑定,INADDR_ANY 表示监听所有网卡

    • recvfrom():阻塞等待客户端数据,同时获取客户端地址

    • sendto():将数据原样发回给客户端

    客户端 client.c

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <stdlib.h>

    int main(void)
    {
    char buff[BUFSIZ];

    // 1. 创建 UDP 套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
    perror("socket failed.");
    exit(1);
    }

    // 2. 设置服务器地址
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(9999);
    serveraddr.sin_addr.s_addr = INADDR_ANY; // 接受任意网卡的数据

    // 3. 绑定地址
    int ret = bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    if (ret == -1) {
    perror("bind failed.");
    exit(1);
    }

    // 4. 循环接收并回复
    while (1) {
    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);

    // 接收客户端数据
    int n = recvfrom(sockfd, buff, sizeof(buff), 0,
    (struct sockaddr*)&clientaddr, &len);
    if (n < 0) {
    perror("recvfrom failed.");
    continue;
    }

    printf("收到来自 %s:%d 的数据: %s\\n",
    inet_ntoa(clientaddr.sin_addr),
    ntohs(clientaddr.sin_port), buff);

    // 回复客户端
    sendto(sockfd, buff, n + 1, 0,
    (struct sockaddr*)&clientaddr, len);
    }

    close(sockfd);
    return 0;
    }

    代码解析:

    • 客户端不需要 bind(),系统自动分配临时端口

    • sendto() 指定目标地址发送数据

    • recvfrom() 接收服务器回复


    总结

    三种通信模式对比

    模式目标地址接收方要求通信范围
    单播 具体IP bind 一对一
    广播 255.255.255.255 bind 本子网所有主机
    组播 224.0.0.88 bind + IP_ADD_MEMBERSHIP 加入组的主机

    核心口诀

    • 广播接收:bind即可 ✅

    • 组播接收:bind + IP_ADD_MEMBERSHIP才行 ✅

    • 广播发送:setsockopt(SO_BROADCAST) + sendto ✅

    • 组播发送:只需sendto(组播地址) ✅

    关键区别

    问题广播组播
    发送方是否需要bind 不需要 不需要
    发送方是否需要特殊设置 需要SO_BROADCAST 不需要
    接收方是否需要bind 必须 必须
    接收方是否需要加入组 不需要 必须
    网络设备如何处理 无差别转发 只转发给订阅者

    常用接口总结

    接口适用场景
    recvfrom UDP接收数据
    sendto UDP发送数据
    setsockopt(SO_BROADCAST) 开启广播发送
    setsockopt(IP_ADD_MEMBERSHIP) 加入组播组
    setsockopt(IP_DROP_MEMBERSHIP) 离开组播组

    掌握UDP广播与组播编程,能帮助你应对局域网消息推送、实时通信、视频直播等多种场景的开发需求。

    赞(0)
    未经允许不得转载:171主机测评 » Linux网络编程:UDP组播与广播深度详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址