多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Windows 平台下的 UDP 客户端

Windows 平台下的 UDP 客户端 本次核心目标验证Windows 平台 UDP 客户端能够正常向Linux 平台 UDP 服务端发送、接收消息完成跨系统 UDP 双向通信。之前文章的实操、测试都是使用本地 Linux 客户端连接我们自己提供的 UDP 服务端。但实际开发、日常使用场景里Windows 才是客户端最主流的运行载体因此我们必须验证Windows 编写的 UDP 套接字代码能够和 Linux 服务端正常连通这是我们的核心验证目标。在正式写代码、做测试前先给大家铺垫底层网络原理 不同操作系统Windows、Linux底层的TCP/IP 协议栈标准完全统一UDP、TCP、IP 协议都内置在操作系统内核中这是跨系统通信的基础。 各系统的驱动、进程管理等模块差异很大但网络编程接口、系统调用逻辑高度一致仅存在少量平台专属特殊 API整体差别很小。下面我们直接进入实操验证环节。我已经提前给大家准备好整套 UDP 实验代码分为两部分Linux UDP 服务端代码已提前就绪我们先在 Linux 服务器启动服务端程序监听端口等待客户端接入UDP 服务端https://rosetea.blog.csdn.net/article/details/147465441Windows UDP 客户端配套客户端代码提前编写完成接下来我们逐行阅读代码区分跨平台代码的通用逻辑与Windows 专属差异点。#include iostream #include cstdio #include thread #include string #include cstdlib #include WinSock2.h #include Windows.h #pragma warning(disable : 4996) #pragma comment(lib, ws2_32.lib) std::string server_ip 192.168.10.129; uint16_t server_port 8888; int main() { WSADATA wsd; // 初始化Winsock if (WSAStartup(MAKEWORD(2, 2), wsd) ! 0) { std::cout WSAStartup 初始化失败 std::endl; return 1; } struct sockaddr_in server; memset(server, 0, sizeof(server)); server.sin_family AF_INET; server.sin_port htons(server_port); server.sin_addr.s_addr inet_addr(server_ip.c_str()); SOCKET sockfd socket(AF_INET, SOCK_DGRAM, 0); if (sockfd SOCKET_ERROR) { std::cout socket 创建失败, 错误码: WSAGetLastError() std::endl; WSACleanup(); return 1; } std::string message; char buffer[1024]; while (true) { std::cout Please Enter ; std::getline(std::cin, message); if (message.empty()) continue; // 增加退出逻辑输入exit关闭程序 if (message exit) break; // 发送UDP报文 int sendRet sendto(sockfd, message.c_str(), (int)message.size(), 0, (struct sockaddr*)server, sizeof(server)); if (sendRet SOCKET_ERROR) { std::cout sendto 发送失败,错误码: WSAGetLastError() std::endl; continue; } struct sockaddr_in temp; int len sizeof(temp); // 等待服务端回包 int s recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)temp, len); if (s 0) { buffer[s] \0; std::cout 服务端返回: buffer std::endl; } else if (s 0) { std::cout 对方关闭连接 std::endl; } else { // 无数据不报错UDP无回包属于正常情况 // std::cout 未收到回包 std::endl; } } // 正常释放资源 closesocket(sockfd); WSACleanup(); return 0; }Windows 与 Linux 套接字通用代码逻辑定义填充struct sockaddr_in结构体写入目标 Linux 服务器 IP、监听端口示例默认端口8888需要和 Linux 服务端绑定端口保持统一创建 UDP 套接字调用socket(AF_INET, SOCK_DGRAM, 0)返回套接字标识 Windows 中套接字类型为SOCKET本质是整数是 Windows 对 Linux 文件描述符的封装如果创建失败会返回SOCKET_ERROR错误标识客户端主循环收发逻辑从控制台读取输入消息空输入直接跳过不发送调用sendto()发送数据参数包含套接字、消息字符串、消息长度、发送标识、服务端地址结构体UDP 客户端无需手动 bind 绑定本地端口首次发送报文时系统会自动分配临时端口服务端回包接收逻辑 定义struct sockaddr_in存储对端地址获取地址长度调用recvfrom()读取服务端返回数据同时拿到服务端 IP 与端口信息接收缓冲区收到数据后手动补字符串结束符\0打印输出。sendto()、recvfrom()两个核心收发接口参数定义、使用流程和 Linux 平台完全相同数据处理逻辑无区别这部分不再重复讲解。Windows 套接字专属差异化代码Windows 编写套接字程序和 Linux 存在三处核心差异全部是平台专属固定写法差异 1头文件与依赖库引入WinSock2.h是 Windows Sockets API 专用头文件用于 Windows 平台网络编程包含 Windows Sockets 2 所需全部数据类型、函数声明、结构体定义是 Windows 套接字开发必备头文件。配套依赖库ws2_32.lib程序编译链接阶段必须引入该库否则运行时会找不到 Winsock 相关 API 函数代码中通过#pragma comment(lib, ws2_32.lib)自动链接。WinSock2.h 核心类型与函数WSADATA结构体存储 Winsock 库初始化后的返回信息SOCKET套接字句柄类型唯一标识程序内的网络套接字sockaddr_inIPv4 专用地址结构体存放 IP、端口、地址族等信息socket()创建套接字bind()将套接字绑定本地 IP 与端口listen()TCP 服务端专用设置套接字监听客户端连接accept()TCP 服务端专用接收客户端连接并返回通信套接字。所以 Linux 网络编程依赖sys/socket.h、netinet/in.h等系统头文件Windows 不提供这类头文件必须做两件事引入头文件WinSock2.h、Windows.h其中WinSock2.h是 Windows 套接字 API 核心头文件链接静态库预处理指令#pragma comment(lib, ws2_32.lib)VS 环境默认自带该库这条语句为固定写法作用是编译时自动链接套接字依赖库屏蔽安全警告#pragma warning(disable : 4996)VS 会默认判定cin、scanf等 IO 接口不安全该语句直接关闭 4996 号警告不影响程序功能。头文件与库文件一一对应缺一不可是 Windows 套接字程序运行的基础。差异 2Winsock 库初始化WSAStartup()所有 Windows 套接字 API 调用前必须先执行该函数负责初始化 Winsock 网络库。参数说明wVersionRequested指定需要使用的 Winsock 版本常用宏MAKEWORD(主版本, 次版本)示例MAKEWORD(2,2)lpWSADataWSADATA结构体指针接收初始化返回的库信息。返回值调用成功返回 0非 0 值代表初始化失败无法使用网络接口。作用告知操作系统当前程序使用的 Winsock 版本完成网络库初始化初始化后才能调用地址转换、套接字收发、连接管理等网络功能实现程序与底层网络协议栈交互。Linux 无需手动初始化网络库Windows 使用套接字 API 前必须手动指定 Winsock 库版本并初始化定义WSADATA结构体用于接收库初始化返回信息调用WSAStartup(MAKEWORD(2, 2), wsd)指定使用Winsock 2.2版本编译器会自动在ws2_32.lib中匹配对应版本库 所有套接字收发操作必须在WSAStartup()初始化成功后执行。差异 3套接字关闭与资源释放套接字关闭Linux 使用close()关闭文件描述符Windows 专用接口closesocket()关闭套接字句柄库资源清理程序全部网络操作结束后调用WSACleanup()释放WSAStartup()加载的 Winsock 库资源避免句柄、内存泄漏。总结Windows UDP 套接字编程99% 业务逻辑和 Linux 通用仅需额外处理头文件、库链接、库初始化、资源释放四组 Windows 专属代码。课件中已经对WinSock2.h、WSADATA、SOCKET等类型做完整注释说明大家课后自行查阅课堂不再逐字朗读。实操打开 VS2022新建空项目项目名称自定义示例命名test_udp_client在项目「源文件」目录新建 C 源文件命名udp_client.cc将上面准备好的 Windows UDP 客户端完整代码粘贴至文件内修改代码关键参数serverip变量填写你自己的云服务器公网 IPserverport保持8888和 Linux 服务端监听端口统一保存代码按下 F5 编译运行客户端程序。Linux 端提前启动 UDP echo 服务端程序./udp_server 8888Windows 客户端启动后控制台提示输入消息输入内容例如 “你好”发送双向通信现象Windows 客户端收到 Linux 服务端原样回显的消息Linux 服务端打印收到的消息同时输出 Windows 客户端对应的公网 IP、临时端口号 由此证明Windows 客户端与 Linux 服务端双向 UDP 通信完全正常。[2026-07-27 02:44:43] [INFO] [26081] [../Common/UdpServer.hpp] [37] - create socket success, sockfd 3 [2026-07-27 02:44:43] [INFO] [26081] [../Common/UdpServer.hpp] [61] - bind socket success, port 8888 [2026-07-27 02:45:03] [DEBUG] [26081] [../Common/UdpServer.hpp] [80] - peer_ip 192.168.10.1, buffer 你好细节 1中文消息编码显示不一致问题Windows 控制台、Linux 终端默认字符编码不同Windows 多为 GBK 编码Linux 系统多为 UTF-8 编码。 发送中文 “你好” 时Windows 本地回显正常但 Linux 服务端打印中文会出现乱码。注意乱码仅为终端显示问题不影响数据传输。服务端仅原样转发数据原始字节完整传输客户端接收后仍可正常展示中文无需修改传输逻辑。细节 2服务端打印的客户端 IP 不是本机局域网 IP有同志会疑惑在 Windows CMD 执行ipconfig查到的本机局域网 IP和 Linux 服务端打印的客户端 IP 不一致这里给大家简单解释原理Ethernet adapter VMware Network Adapter VMnet8: Connection-specific DNS Suffix . : Link-local IPv6 Address . . . . . : fe80::3f62:3c5d:5be0:97f8%6 IPv4 Address. . . . . . . . . . . : 192.168.10.1 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : Wireless LAN adapter WLAN: Connection-specific DNS Suffix . : IPv6 Address. . . . . . . . . . . : 2409:8a34:4e32:86e0:bcae:d879:265d:f95f Temporary IPv6 Address. . . . . . : 2409:8a34:4e32:86e0:99a4:400e:119e:e46a Link-local IPv6 Address . . . . . : fe80::47a9:cd49:ac0c:71ed%17 IPv4 Address. . . . . . . . . . . : 192.168.1.22 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : fe80::1%17 192.168.1.1我们家用、校园网环境下Windows 主机处于局域网内网 IP 仅局域网内生效报文向外网云服务器发送时会经过运营商移动 / 联通 / 电信网关、出口路由器做 NAT 地址转换Linux 云服务器收到报文时记录的是运营商出口公网 IP而非 Windows 本机局域网 IP运营商网关会记录内网主机与公网端口映射关系服务端回包可通过该映射原路传回 Windows 客户端。现阶段大家只需记住二者 IP 不一致属于正常现象后续接触到 NAT、内网穿透、代理服务器时会完整拆解该机制。本次实验完成验证Windows UDP 客户端可以正常向 Linux 服务端发起 UDP 数据交互。 现实业务场景举例直播平台使用 UDP 传输实时数据流后端服务全部部署在 Linux 服务器我们日常使用 Windows 电脑观看直播、发送弹幕底层就是本次验证的跨平台 UDP 通信逻辑。很多同志复制同款代码可能依旧无法连通90% 原因是云服务器端口未放行 云服务器默认安全组、防火墙会拦截所有未主动开放端口示例使用端口 8888需要前往阿里云 / 腾讯云 / 华为云后台找到「安全组」配置手动放行8888 端口入站流量。大家可以自行搜索引擎查询云服务器安全组配置教程建议大家独立尝试操作。
返回列表