select()返回10038错误:Windows Socket非套接字操作问题求助
解决select()返回10038错误(非套接字操作)的问题
错误原因
你遇到的10038错误,核心问题出在Windows平台下的select()不支持同时监听套接字和标准输入(文件描述符)。Windows里的套接字和普通文件描述符是两套独立的机制,你把代表标准输入的0放进fd_set里,select()会把它当成套接字处理,自然就报“对非套接字执行操作”的错误。另外你调用select时第一个参数传0也是错的,这个参数应该是所有监听套接字里的最大值加1。
解决方案
针对Windows平台,有两种常见的处理方式:
方式1:用WaitForMultipleObjects同时监听套接字和控制台输入
Windows提供的WaitForMultipleObjects API可以同时等待多个内核对象,包括套接字和控制台输入事件,示例代码修改如下:
... // 获取标准输入的句柄 HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); HANDLE handles[2]; handles[0] = (HANDLE)sock; // Windows套接字可直接转换为HANDLE handles[1] = hStdin; while (true) { // 等待1秒超时,不等待所有对象触发 DWORD dwWaitResult = WaitForMultipleObjects(2, handles, FALSE, 1000); switch (dwWaitResult) { case WAIT_OBJECT_0: { // 套接字有数据到达 memset(buffer, 0, sizeof(buffer)); int bytesReceived = recv(sock, buffer, sizeof(buffer), 0); if (bytesReceived > 0) { cout << buffer << endl; } else if (bytesReceived == 0) { cout << "Connection closed by server" << endl; break; } else { cerr << "Failed to receive data: " << WSAGetLastError() << endl; break; } break; } case WAIT_OBJECT_0 + 1: { // 控制台有输入 getline(cin, response); if (send(sock, response.c_str(), response.size(), 0) == SOCKET_ERROR) { cerr << "Failed to send data: " << WSAGetLastError() << endl; break; } response = ""; break; } case WAIT_TIMEOUT: // 超时,继续循环 break; default: cerr << "Wait failed: " << GetLastError() << endl; break; } } ...
方式2:分开处理套接字和控制台输入(轮询检查)
如果不想使用多对象等待,可以用_kbhit()检查控制台是否有输入,结合select()处理套接字,避免两者混用:
... while (true) { FD_ZERO(&readfds); FD_SET(sock, &readfds); timeout.tv_sec = 0; timeout.tv_usec = 100000; // 100ms超时,降低轮询频率 // 第一个参数改为最大套接字值+1 int activity = select(sock + 1, &readfds, nullptr, nullptr, &timeout); if (activity == SOCKET_ERROR) { cerr << "Select failed: " << WSAGetLastError() << endl; break; } if (FD_ISSET(sock, &readfds)) { // 处理套接字数据,逻辑和原代码一致 memset(buffer, 0, sizeof(buffer)); int bytesReceived = recv(sock, buffer, sizeof(buffer), 0); if (bytesReceived > 0) { cout << buffer << endl; } else if (bytesReceived == 0) { cout << "Connection closed by server" << endl; break; } else { cerr << "Failed to receive data: " << WSAGetLastError() << endl; break; } } // 检查控制台是否有输入 if (_kbhit()) { getline(cin, response); if (send(sock, response.c_str(), response.size(), 0) == SOCKET_ERROR) { cerr << "Failed to send data: " << WSAGetLastError() << endl; break; } response = ""; } } ...
额外注意点
- 确保
sock是通过socket()或accept()创建的有效Windows套接字,无效套接字也可能触发10038错误。 - 方式1中,套接字转HANDLE的操作仅适用于WSAAPI创建的套接字,避免兼容性问题。
内容的提问来源于stack exchange,提问作者sech1p
相关产品推荐
相关产品推荐

