You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 07:58:16