Windows 平台下的 TCP 客户端

Windows 平台下的 TCP 客户端 本次实操验证核心目标Windows 平台 TCP 客户端能够正常连通 Linux TCP 服务端。我们已经完整讲解过 TCP 套接字基础写法配套实验也完成过 Linux 机器与 Linux 机器之间同平台 TCP 通信。socket 套接字 - TCPhttps://rosetea.blog.csdn.net/article/details/147653994此前我们实践过 Windows UDP 客户端连通 Linux 服务端同理TCP 通信也必须实现 Windows 客户端跨平台连通 Linux 服务端Windows 平台下的 UDP 客户端https://rosetea.blog.csdn.net/article/details/163220666如果无法完成跨平台互通这套套接字通信方案就不具备实用价值所以本次专门带大家完整落地这套跨平台 TCP 通信流程。一、Windows TCP 客户端代码通用固定框架说明Windows 下 Winsock 套接字基础流程和之前 UDP 完全一致核心固定步骤没有任何区别引入头文件winsock2.h通过#pragma comment(lib, ws2_32.lib)链接 Winsock 库调用WSAStartup()初始化 Winsock 版本环境接收WSADATA版本信息程序结束时调用WSACleanup()释放网络资源头文件内置核心类型与函数名称作用说明WSADATA存储 Winsock 库初始化返回的系统信息SOCKET套接字句柄唯一标识一个网络套接字sockaddr_inIPv4 专用地址结构体存放 IP、端口等地址信息socket()创建套接字对象bind()将套接字绑定本地 IP 与端口listen()把套接字切换为监听模式等待客户端连接accept()接收客户端连接返回专用通信套接字WSAStartup函数定位Windows 套接字库初始化函数所有 Socket 相关 API 调用前必须优先执行是 Windows 网络程序入口初始化步骤。参数说明wVersionRequested指定程序需要使用的 Winsock 版本固定搭配宏MAKEWORD(主版本, 次版本)示例代码使用MAKEWORD(2,2)代表 Winsock 2.2 版本lpWSADataWSADATA 结构体指针用于接收系统返回的初始化详情。返回值规则返回0初始化成功可正常使用 Socket 接口非 0 数字初始化失败数字为对应错误码。核心功能告知操作系统当前程序要使用指定版本的 Winsock 网络库完成库资源初始化初始化完成后程序才能调用地址解析、连接、收发数据等全套网络功能实现应用层与系统 TCP/IP 协议栈交互。配套释放接口程序不再使用 Socket 功能时必须调用WSACleanup()解除程序与 Winsock 库绑定释放系统占用的网络资源避免内存 / 句柄泄漏。本次重点对比Windows 平台 TCP Client 代码 和 Linux 平台原生 TCP Client 代码的区别。结论二者差异极小99% 代码逻辑、流程完全一致。1. 套接字创建流程前置初始化完成后直接固定写法创建套接字socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);地址族参数AF_INET套接字类型SOCK_STREAM面向连接 TCP 流协议参数可填0自动适配也可显式填写IPPROTO_TCP两种写法均可Linux 平台套接字句柄为普通int类型Windows 平台专用类型SOCKET创建失败时会返回内置宏INVALID_SOCKET程序中需要做失败判断处理。2. 填充服务端地址与连接逻辑客户端需要手动填充服务端端口、IP 地址信息使用结构体sockaddr_in 调用connect()发起连接传入强制转换后的套接字地址指针connect(clientSocket, (SOCKADDR *)serverAddr, sizeof(serverAddr));Windows 平台相关类型、宏名称大多为大写如SOCKADDR、SOCKET底层对应 Linux 里小写的sockaddr、文件描述符仅语法标识区分逻辑完全相同。连接返回SOCKET_ERROR代表连接失败需要关闭套接字、清理 Winsock 资源后退出程序。3. 循环收发数据逻辑建立连接后进入业务主循环完整流程获取控制台用户输入空输入直接跳过本次循环调用send()向服务端发送数据参数依次为套接字句柄、消息字符串、消息字节长度、发送标识0定义buffer缓冲区调用recv()读取服务端回传数据参数为套接字、缓冲区、缓冲区长度减 1、读取标识0判断recv()返回值返回值 0读取到有效数据手动给缓冲区末尾追加\0转为标准字符串打印服务端回显内容返回值≤0读取失败、连接断开打印错误提示整体收发逻辑和之前 UDP 客户端、Linux 原生 TCP 客户端完全统一没有额外复杂逻辑此处不重复展开。完整客户端代码#include winsock2.h #include ws2tcpip.h // 新增用于inet_pton #include iostream #include string #pragma warning(disable : 4996) #pragma comment(lib, ws2_32.lib) std::string serverip 113.132.212.215; // 替换为你的云服务器ip uint16_t serverport 8888; // 填写你的云服务开放的端口号 int main() { WSADATA wsaData; int result WSAStartup(MAKEWORD(2, 2), wsaData); if (result ! 0) { std::cerr WSAStartup failed: result std::endl; return 1; } SOCKET clientSocket socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (clientSocket INVALID_SOCKET) { std::cerr socket failed std::endl; WSACleanup(); return 1; } sockaddr_in serverAddr{}; serverAddr.sin_family AF_INET; serverAddr.sin_port htons(serverport); // 替换废弃的inet_addr使用安全的inet_pton if (inet_pton(AF_INET, serverip.c_str(), serverAddr.sin_addr) 0) { std::cerr IP地址格式错误 std::endl; closesocket(clientSocket); WSACleanup(); return 1; } result connect(clientSocket, (SOCKADDR *)serverAddr, sizeof(serverAddr)); if (result SOCKET_ERROR) { std::cerr connect failed std::endl; closesocket(clientSocket); WSACleanup(); return 1; } bool runFlag true; while (runFlag) { std::string message; std::cout Please Enter ; std::getline(std::cin, message); if(message.empty()) continue; // 增加send发送结果校验 int sendRet send(clientSocket, message.c_str(), message.size(), 0); if (sendRet SOCKET_ERROR) { std::cerr send 发送失败连接断开 std::endl; break; } char buffer[1024] {0}; int bytesReceived recv(clientSocket, buffer, sizeof(buffer) - 1, 0); if (bytesReceived 0) { buffer[bytesReceived] \0; std::cout Received from server: buffer std::endl; } else { // recv返回0服务端关闭连接返回负数网络异常 std::cerr recv failed服务端已断开连接 std::endl; runFlag false; } } // 循环退出后正常释放资源 closesocket(clientSocket); WSACleanup(); std::cout 客户端正常退出 std::endl; return 0; }二、实操验证完整流程阶段 1提前启动 Linux TCP Echo 服务端我们提前准备好配套 TCP 服务端源码端口统一使用8888。 服务端本质是标准 Echo 回显服务器核心逻辑创建套接字 → bind 绑定端口 → listen 开启监听通过accept()阻塞等待客户端新连接获取专属通信套接字、客户端 IP 与端口信息循环读取客户端发送的数据读完后原样写回客户端echo 回显服务端代码基础流程之前文章已经完整本次不再细读源码直接启动 Linux 服务端程序保持后台监听状态。阶段 2VS20XX 创建 Windows TCP 客户端工程实操打开 Visual Studio新建空 C 项目自定义项目名称示例test右键项目添加新建源文件命名为tcp_client.cpp/tcp_client.cc均可复制课件内完整 Windows TCP Client 代码粘贴至源文件注意区分 TCP、UDP 代码避免粘贴错误修改代码内两处关键配置serverip填写你自己的云服务器公网 IP演示使用讲师云服务器 IP学员需替换为自身机器地址serverport固定 8888与 Linux 服务端监听端口保持一致阶段 3编译运行、双向通信测试代码配置完成后按下F5启动客户端程序程序启动自动执行WSAStartup、创建套接字、调用connect连接 Linux 服务端Linux 服务端日志会立刻打印新接入客户端的公网 IP、随机临时端口代表跨平台 TCP 连接建立成功在 Windows 客户端控制台输入任意文本消息例如hello、你好、在吗等Windows 客户端通过 TCP 将数据发送至 Linux 服务端Linux 服务端读取数据后原样回传Windows 客户端recv()读取回显内容并打印双向通信验证完成IP 地址、端口开放、防火墙放行等注意事项UDP 相关中已经重点强调本次不再重复说明。三、核心断线检测逻辑客户端退出服务端自动感知TCP 协议具备连接状态感知能力这是本篇重点补充的关键特性 Windows 客户端主动关闭程序 / 断开套接字时Linux 服务端执行recv()读取操作会直接返回0服务端可以精准识别客户端下线。服务端断线处理逻辑说明服务端处理新连接的循环中对recv()返回值做分支判断返回值 0正常读取到客户端消息执行 echo 回显返回值≤0判定客户端主动断开连接打印日志格式[客户端IP:端口] client quit演示效果关闭 Windows 客户端程序后Linux 服务端控制台立刻输出对应客户端退出日志证明跨平台 TCP 连接断开事件可被两端正常识别。四、实操总结本次完整实操验证了基于 Winsock 实现的 Windows TCP 客户端能够和 POSIX 标准 Linux TCP 服务端完成稳定跨平台 TCP 双向通信连接建立、数据收发、断线检测全流程均可正常运行。Windows 与 Linux 套接字仅初始化、资源释放、类型标识存在少量平台专属差异通信核心逻辑完全通用大家后续开发跨平台 TCP 程序可直接复用这套代码框架。