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


第一部分:UDP基础与核心接口详解
1.1 UDP协议概述
UDP(User Datagram Protocol,用户数据报协议)是一种面向无连接的传输层协议。与TCP不同,UDP在传输数据前不需要建立连接,可以直接通信。
UDP核心特点
| 无连接 | 发送数据前不需要建立连接 |
| 不可靠 | 不保证到达、不保证顺序、不保证不重复 |
| 速度快 | 无握手、无确认、无重传 |
| 面向报文 | 保留消息边界,一次发送对应一次接收 |
| 支持广播/组播 | 可向多个目标同时发送数据 |
UDP与TCP对比
| 连接方式 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠(确认、重传、排序) | 不可靠 |
| 传输速度 | 较慢 | 较快 |
| 数据边界 | 字节流,无边界 | 数据报,有边界 |
| 首部开销 | 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 的区别
一、核心区别
| 有数据时 | 立即返回 | 立即返回 |
| 无数据时 | 一直等待(卡住) | 立即返回 -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?
| 发送方 | 不需要 | 只是"喊话",不需要别人找到它 |
| 接收方 | 必须 | 要被广播包"送达",必须占固定端口 |
类比:村支书用大喇叭喊话(发送方不需要告诉别人自己在哪),村民必须待在固定频率收听(接收方必须占坑)。
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 | 仅指定网卡 | ⚠️ 部分能 |
实验验证:
| 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广播与组播编程,能帮助你应对局域网消息推送、实时通信、视频直播等多种场景的开发需求。


