udp服务端必须调用bind绑定本地端口以接收数据,客户端可不显式bind但系统自动分配临时端口;收发必须使用recvfrom和sendto并指定地址,不可用read/write或recv/send。

UDP通信必须先创建socket并绑定端口
服务端要接收数据,socket 必须用 bind 绑定本地地址和端口;客户端虽然可以不显式 bind,但系统会自动分配临时端口,若需复用端口或指定源地址,也得调用 bind。常见错误是服务端忘了 bind,导致 recvfrom 一直阻塞或返回 -1,errno 为 EBADF 或 EINVAL。
关键点:
-
socket(AF_INET, SOCK_DGRAM, 0)创建 UDP socket,不能用SOCK_STREAM - 服务端
bind()前需填充sockaddr_in:注意sin_addr.s_addr = INADDR_ANY允许接收任意网卡来的包 - 客户端若想让服务端能回包,必须确保
sendto的目标地址非INADDR_ANY,且端口与服务端一致 - Linux 下若端口被占用,
bind失败返回-1,errno是EADDRINUSE,可设SO_REUSEADDR选项避免
收发数据要用recvfrom和sendto,不是read/write
UDP 是无连接协议,每次收发都要明确对方地址,所以不能用面向连接的 read/write 或 recv/send(后者默认使用已连接的对端,而 UDP socket 默认未连接)。必须用带地址参数的 recvfrom 和 sendto。
典型误用:
- 服务端用
recv等待数据 → 返回-1,errno为ENOTCONN - 客户端调用
connect后改用send→ 虽然可行,但掩盖了 UDP 本质,且无法接收非目标地址的响应包 -
recvfrom的addrlen参数传入前未初始化为sizeof(sockaddr_in)→ Windows 下可能崩溃,Linux 下常返回0字节
示例片段(服务端接收):
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
ssize_t n = recvfrom(sockfd, buf, sizeof(buf)-1, 0,
(struct sockaddr*)&client_addr, &addr_len);
if (n > 0) {
buf[n] = '\0';
printf("Received from %s:%d: %s\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port),
buf);
}
需要手动处理地址转换和字节序
C++ 网络编程里,IP 地址和端口必须按网络字节序(大端)传给 socket API,而 x86/x64 主机是小端,直接赋值会导致地址错乱或端口异常(比如本意发到 8080,实际发到 32768)。所有涉及 sin_port、sin_addr.s_addr 的赋值都得过 htons/htonl。
容易忽略的点:
-
inet_addr("127.0.0.1")返回的是网络字节序,可直接赋给sin_addr.s_addr;但字符串转 IP 更推荐inet_pton,支持 IPv6 且更安全 -
ntohs/ntohl用于从接收到的数据中还原主机字节序,比如解析客户端发来的端口号字段 - 服务端回包时,必须把
client_addr原样传给sendto,不能只改sin_port—— UDP 每次通信都是独立的,地址信息不能丢
没有超时机制,阻塞模式下recvfrom会一直等
默认 socket 是阻塞的,recvfrom 在没数据时挂起线程,导致程序卡死。生产环境必须加超时控制,要么用 select,要么设 socket 为非阻塞,要么用 setsockopt 配置 SO_RCVTIMEO。
推荐做法:
- 简单场景用
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)),其中tv是struct timeval,设为 {1, 0} 表示 1 秒超时 -
recvfrom返回-1且errno == EAGAIN || errno == EWOULDBLOCK即表示超时,不是错误 - 别在循环里反复
recvfrom不检查返回值 —— 若对方没发,你可能空跑几百次 CPU - 多客户端场景下,一个服务端 socket 可同时服务多个客户端,靠
recvfrom返回的client_addr区分来源,无需为每个客户端建新 socket
UDP 本身不保证送达、不排序、不重传,应用层若需可靠性,得自己加序列号、ACK 和重发逻辑——这已经超出“简单通讯”范畴了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










