Windows 平台 TCP 通信开发指南
开篇介绍
在 Windows 平台进行 TCP 通信开发,是网络编程中的常见需求。本文将详细讲解在 Windows 平台下,如何利用 Winsock API 实现高效的 TCP 客户端与服务端通信。
使用示例
必须引入的头文件
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")// 自动链接库文件
1)环境初始化
共同实现
// 所有网络程序必须先初始化Winsock
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
独有实现
服务端初始化
// 服务端需指定监听地址和端口
sockaddr_in server_addr{}; //C++11方式初始化为0,不需要额外调用 memset
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有IP
server_addr.sin_port = htons(12345); // 指定端口 转换网络字节序
客户端初始化
// 客户端需明确目标地址,连接服务端
sockaddr_in server_addr{}; //C++11方式初始化
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务端IP
server_addr.sin_port = htons(12345); // 服务端端口
2)Socket创建
共同实现
// 创建TCP流式Socket(IPv4协议族)
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
3)连接建立
服务端独有流程
// 绑定地址到Socket
bind(server_socket, (SOCKADDR*)&server_addr, sizeof(server_addr));// 开启监听模式
listen(server_socket, 5); // 最大等待队列长度// 接受客户端连接(阻塞式)
SOCKET client_socket;
sockaddr_in client_addr{};
int addr_len = sizeof(client_addr);
client_socket = accept(server_socket, (SOCKADDR*)&client_addr, &addr_len);
客户端独有流程
// 主动发起连接请求
connect(client_socket, (SOCKADDR*)&server_addr, sizeof(server_addr));
关键判断
if (connect() == SOCKET_ERROR)
// 处理连接失败
4)数据传输
服务端独有逻辑
// 通常先发送欢迎信息
send(client_socket, welcome_msg, strlen(welcome_msg) + 1, 0);// 持续接收客户端请求
while (true) {recv(client_socket, buffer, sizeof(buffer), 0);// 处理业务逻辑send(client_socket, response, response_len, 0);
}
客户端独有逻辑
// 接收服务端初始响应
recv(client_socket, buffer, sizeof(buffer), 0);// 持续交互循环
while (true) {// 获取用户输入send(client_socket, input_data, data_len, 0);// 等待服务端响应recv(client_socket, response, sizeof(response), 0);
}
共同核心方法
// 发送数据
int sent_bytes = send(sock, data, data_len, 0);// 接收数据
int recv_bytes = recv(sock, buffer, buf_size, 0);
关键判断
if (recv_bytes <= 0)
// 连接异常或关闭
if (sent_bytes == SOCKET_ERROR)
// 发送失败处理
5)连接终止
服务端
// 需关闭两个 Socket
closesocket(client_socket);
closesocket(server_socket);
客户端
closesocket(client_socket); //关闭客户端即可
共同操作
// 所有网络程序必须释放资源
WSACleanup();
总结流程图
[客户端] [服务端]
WSAStartup WSAStartup
socket() socket()
connect() → → → → → → → → → → bind()listen()accept()
send()/recv() ↔ ↔ ↔ ↔ ↔ ↔ ↔ ↔ recv()/send()
closesocket() closesocket()
WSACleanup WSACleanup
快速测试方法
- 运行服务端程序
- 用 Telnet 测试:
telnet 127.0.0.1 12345
关键步骤对比
步骤 | 服务端 | 客户端 |
---|---|---|
1. 初始化 | WSAStartup | WSAStartup |
2. 创建Socket | socket() | socket() |
3. 绑定端口 | bind() (必须) | × |
4. 建立连接 | listen() → accept() | connect() |
5. 收发数据 | send() /recv() | send() /recv() |
6. 关闭连接 | closesocket() | closesocket() |
关于
sock
的理解?在发送和接收数据时,
sock
是用于通信的套接字对象。其具体含义取决于当前的操作是在客户端还是服务端进行:
- 在服务端 :当服务端调用
accept()
函数接受客户端的连接请求后,会返回一个新的套接字,即client_socket
。在这个新的套接字上进行send()
和recv()
操作,发送和接收的是与该特定客户端通信的数据。这个client_socket
就是与客户端通信的套接字。- 在客户端 :客户端调用
connect()
函数与服务端建立连接后,使用的sock
是客户端自己的套接字,通过它与服务端进行数据通信。所以,不管是在客户端还是服务端,
send()
和recv()
函数中的sock
都是代表与对方通信的套接字,用于在双方之间传输数据。
掌握这些核心要点,即可快速实现 Windows 平台的 TCP 双工通信。建议结合 Wireshark 抓包工具进行协议分析调试。