UDP通信必须先创建socket并绑定端口,否则recvfrom会失败;Linux返回EBADF,Windows返回WSAENOTSOCK;关键步骤为:socket→填充sockaddr_in→bind→recvfrom,且recvfrom的src_addr和addrlen参数不可为空,须初始化并用于获取发送方地址。

UDP通信必须先创建socket并绑定端口
不绑定端口就调用 recvfrom 会失败,返回错误码 WSAENOTSOCK(Windows)或 EBADF(Linux),本质是 socket 描述符未正确初始化。Linux 下还要注意:若绑定到 INADDR_ANY,需确保没其他进程占用了目标端口;Windows 上如果启用了防火墙,默认会拦截 UDP 入站包,得手动放行。
关键步骤顺序不能乱:
- 调用
socket(AF_INET, SOCK_DGRAM, 0)创建 UDP socket - 填充
sockaddr_in结构体,sin_port必须用htons()转换(比如htons(8080)) - 调用
bind()绑定本地地址,失败时检查errno或WSAGetLastError()
发送方不用 bind,但必须指定目标地址
UDP 是无连接协议,发送端可以不调用 bind,系统会自动分配临时端口;但 sendto 的第 5、6 个参数(目标地址结构体和长度)缺一不可,否则发出去的包目标 IP 和端口全是 0,对方收不到。
常见误区:
立即学习“C++免费学习笔记(深入)”;
- 误把
sendto的addr参数设为NULL—— 这是 TCP 的写法,UDP 不支持 - 忘记设置
sin_family = AF_INET,导致地址解析失败 - 目标 IP 写成
"127.0.0.1"却在另一台机器上运行接收端,结果包根本没出本机
recvfrom 需要传入地址缓冲区来获取发件人信息
recvfrom 的第 5、6 个参数不是可选的:即使你只关心数据内容,也必须提供非空的 sockaddr_in* 和 socklen_t*,否则函数调用失败,且无法知道是谁发来的。这是 UDP 实现“点对点”的基础——靠每次收到的源地址做回应。
典型用法:
- 定义
struct sockaddr_in src_addr和socklen_t src_len = sizeof(src_addr) - 调用
recvfrom(sockfd, buf, sizeof(buf)-1, 0, (struct sockaddr*)&src_addr, &src_len) - 后续回包时,直接复用
src_addr作为sendto的目标地址
注意:src_len 必须初始化为 sizeof(src_addr),否则 Windows 下可能触发访问违规。
跨平台编译要注意头文件和初始化差异
Linux 直接包含 <sys/socket.h>、<netinet/in.h>、<arpa/inet.h> 就行;Windows 必须先调用 WSAStartup(),且头文件是 <winsock2.h>,链接时加 -lws2_32(GCC)或设置项目依赖(MSVC)。
容易漏掉的点:
- Windows 下忘了调用
WSACleanup(),下次启动程序可能报错WSASYSNOTREADY - Linux 下没加
#define _GNU_SOURCE就用inet_ntop,编译报错 - 发送/接收缓冲区大小建议设为 65507 字节(IPv4 UDP 最大有效载荷),避免 IP 分片
点对点通信的“点”不是靠代码里写死两个 IP 实现的,而是靠运行时动态记录每次 recvfrom 返回的源地址。真要稳定交互,得自己加简单帧头标识消息类型,不然收错包都不知道怎么处理。


















