UDP客户端需绑定本地端口(可设0自动分配)并用sendto()向服务端准确IP和端口发送数据,否则数据被静默丢弃;服务端用recvfrom()接收并原样地址回包,无需connect或维护连接状态。
UDP 是无连接协议,客户端不需要显式 connect(),但必须确保目标地址和端口准确;否则发出去的数据包会被内核静默丢弃,且不会报错。常见错误是误用 INADDR_ANY 或本地未绑定端口,导致服务端回包时无法送达(因为内核找不到对应 socket)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
bind() 绑定一个本地端口(哪怕用 0 让系统自动分配),否则 recvfrom() 会失败或收不到回包inet_addr() 或 inet_pton() 检查 IP 字符串合法性,非法地址会导致 sendto() 返回 -1 且 errno 为 EINVAL
8080,客户端却发到 8081,数据就彻底丢失sendto() 时,addrlen 参数必须是 sizeof(sockaddr_in),传小了会导致地址截断,服务端看到的是乱码 IP单线程 UDP 服务端通常用 recvfrom() 阻塞等待,但这不等于“不能双向通信”——关键在于:每个收到的包都携带源地址信息,服务端可直接用该地址+端口调用 sendto() 回复,无需维护连接状态。
实操建议:
立即学习“C++免费学习笔记(深入)”;
bind();绑定一次即可,重复调用会返回 errno = EADDRINUSE
recvfrom() 后,把拿到的 sockaddr_in 结构体原样传给 sendto(),不要重新构造或修改 sin_port 字段(注意网络字节序已由 recvfrom() 自动填充)sendto() 前对同一 sockaddr_in 调用 htonl() 或 htons() —— 这些字段已是网络序,二次转换会导致端口变成 0recvfrom() 默认阻塞,但若设了 SOCK_NONBLOCK 或 O_NONBLOCK,没数据时会立即返回 -1 并置 errno = EAGAIN 或 EWOULDBLOCK。这不是错误,而是预期行为;盲目重试或忽略它,会导致 CPU 空转或逻辑跳过有效数据。
实操建议:
立即学习“C++免费学习笔记(深入)”;
recvfrom() 返回值:等于 -1 且 errno == EAGAIN 时,应继续下一轮循环,而非报错退出65536(即 UDP 最大理论包长),小于 65507 可能导致大数据包被截断,且不提示ntohl()/ntohs() 解析源 IP 和端口——别依赖打印调试,因为 printf("%d", sin_port) 会显示错误的主机序数值WSAStartup() 初始化,否则所有 socket 函数均失败,错误码为 WSANOTINITIALISED
Linux 和 Windows 对 sockaddr_in 的定义基本一致,但头文件依赖和初始化方式差异明显。最常踩的坑是漏包含、顺序错、或忘记清理资源。
实操建议:
立即学习“C++免费学习笔记(深入)”;
<sys/socket.h>、<netinet/in.h>、<arpa/inet.h>;Windows 必须包含:<winsock2.h>,且 #include <ws2tcpip.h> 在其后WSAStartup(MAKEWORD(2,2), &wsaData),结尾调用 WSACleanup();漏掉任一都会导致后续 socket 创建失败memset(&addr, 0, sizeof(addr)) 必须在声明 sockaddr_in addr 后立即执行,否则 sin_zero 字段可能含垃圾值,影响地址比较或 sendto() 行为close(),Windows 用 closesocket();混用会导致句柄泄漏或崩溃