window下的tcpserver怎么通过客户端的socket句柄判断客户端是否断开连接
时间: 2023-10-02 18:04:25 浏览: 135
在 Windows 平台下开发 TCP 服务器,可以使用 `select()` 函数来判断客户端是否断开连接。`select()` 函数是一个多路复用 I/O 函数,可以监视一组文件描述符,判断它们是否处于可读、可写或异常状态。当 `select()` 函数返回时,通过检查文件描述符的状态,可以得知哪些客户端断开了连接。
下面是一个使用 `select()` 函数来判断客户端是否断开连接的示例代码:
```c++
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
void handle_client(SOCKET client_socket) {
// 处理客户端连接
}
int main() {
// 初始化 Winsock
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
printf("WSAStartup failed\n");
return 1;
}
// 创建服务器套接字
SOCKET server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// 绑定服务器套接字到本地地址和端口
sockaddr_in server_addr = { 0 };
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(12345);
if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
printf("bind failed with error: %ld\n", WSAGetLastError());
closesocket(server_socket);
WSACleanup();
return 1;
}
// 监听连接请求
if (listen(server_socket, SOMAXCONN) == SOCKET_ERROR) {
printf("listen failed with error: %ld\n", WSAGetLastError());
closesocket(server_socket);
WSACleanup();
return 1;
}
// 创建文件描述符集合
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(server_socket, &read_fds);
while (true) {
// 调用 select() 函数检查文件描述符状态
fd_set tmp_fds = read_fds;
if (select(0, &tmp_fds, NULL, NULL, NULL) == SOCKET_ERROR) {
printf("select failed with error: %ld\n", WSAGetLastError());
break;
}
// 依次处理可读文件描述符
for (int i = 0; i < tmp_fds.fd_count; i++) {
if (tmp_fds.fd_array[i] == server_socket) {
// 有新的连接请求
sockaddr_in client_addr = { 0 };
int client_addr_len = sizeof(client_addr);
SOCKET client_socket = accept(server_socket, (sockaddr*)&client_addr, &client_addr_len);
if (client_socket == INVALID_SOCKET) {
printf("accept failed with error: %ld\n", WSAGetLastError());
continue;
}
printf("client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
FD_SET(client_socket, &read_fds);
} else {
// 有客户端发送数据
char buf[1024];
int recv_len = recv(tmp_fds.fd_array[i], buf, sizeof(buf), 0);
if (recv_len == SOCKET_ERROR) {
printf("recv failed with error: %ld\n", WSAGetLastError());
closesocket(tmp_fds.fd_array[i]);
FD_CLR(tmp_fds.fd_array[i], &read_fds);
} else if (recv_len == 0) {
// 客户端已经断开连接
printf("client disconnected\n");
closesocket(tmp_fds.fd_array[i]);
FD_CLR(tmp_fds.fd_array[i], &read_fds);
} else {
// 处理客户端发送的数据
handle_client(tmp_fds.fd_array[i]);
}
}
}
}
// 关闭服务器套接字
closesocket(server_socket);
// 清理 Winsock
WSACleanup();
return 0;
}
```
在上面的代码中,我们先创建了一个文件描述符集合 `read_fds`,将服务器套接字 `server_socket` 添加到集合中。然后在循环中,调用 `select()` 函数检查文件描述符状态。如果 `select()` 函数返回,就遍历可读文件描述符,如果是服务器套接字,表示有新的连接请求,我们就调用 `accept()` 函数创建一个新的客户端套接字,并将其添加到文件描述符集合中。如果是客户端套接字,表示有客户端发送数据,我们就调用 `recv()` 函数接收数据,并根据返回值判断客户端是否已经断开连接。如果客户端已经断开连接,我们就关闭客户端套接字,并从文件描述符集合中删除它。
阅读全文