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

WSA错误10037排查:Winsock2客户端连接服务器失败问题

Winsock2客户端连接报错WSA 10037问题排查

我用Winsock2编写了简单的客户端-服务器连接程序,复用了之前项目中可正常运行的代码,但客户端调用connect连接服务器时持续出现WSA错误10037。已确认连接前调用了init初始化函数,但问题仍存在,且服务器端未收到任何客户端连接请求提示。相关代码如下:

客户端初始化代码

bool Client::init() {
    WSADATA wsa;
    int result = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (result != 0) {
        printf("WSAStartup Failed: %i\n", result);
        return false;
    }
    winSockInit = true;
    clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (clientSocket == INVALID_SOCKET) {
        printf("Socket Creation Failed: %i\n", WSAGetLastError());
        WSACleanup();
        winSockInit = false;
        return false;
    }
    socketInit = true;
    u_long mode = 1;
    result = ioctlsocket(clientSocket, FIONBIO, &mode);
    if (result == SOCKET_ERROR) {
        printf("ioctlsocket Failed: %i\n", result);
        closesocket(clientSocket);
        WSACleanup();
        socketInit = false;
        winSockInit = false;
        return false;
    }
    return true;
}

客户端连接服务器代码

void Client::reset() {
    if (socketInit)
        closesocket(clientSocket);
    if (winSockInit)
        WSACleanup();
    socketInit = false;
    winSockInit = false;
    isConnected = false;
}
bool Client::connectToServer(std::string ip, int port) {
    sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    int result = inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
    if (result != 1) {
        printf("Failed to convert IP address: %i\n", WSAGetLastError());
        reset();
        return false;
    }
    serverIp = ip;
    //Connect to the server
    serverAddr.sin_port = htons(port);
    serverPort = port;
    bool success = false;
    u64 connectAttempts = 0;
    while (connectAttempts < 10 && !success) {
//--------------------------------------------
//Issue On the following line
        result = connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));//<------------------------------This is the issue
//--------------------------------------------      
if (result == SOCKET_ERROR) {
            int error = WSAGetLastError();
            if (error == WSAEISCONN) {
                //printf("Client::Already connected\n");
                success = true;
                break;
            }
            else if (error == WSAEWOULDBLOCK) {//It either runs this
                printf("Blocked\n");
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            else if (error == WSAEALREADY) {//Or this
                printf("WSAEALREADY\n");
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            else {
                printf("Client::Socket Error: %i\n", error);
                reset();
                return false;
            }
        }
        else {
            success = true;
            break;
        }
        connectAttempts++;
    }
    printf("Attempts: %llu\n", connectAttempts);
    if (!success)
        return false;
    isConnected = true;
    return true;
}

服务器端初始化代码

bool Server::init() {
    //WSA stuff
    int result = WSAStartup(MAKEWORD(2, 2), &wsa);
    if (result != 0) {
        std::cerr << "Server::WSAStartup Failed: " << result << std::endl;
        return false;
    }
    //Create the listen socket
    listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listenSocket == INVALID_SOCKET) {
        std::cerr << "Server::Socket Failed: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return false;
    }
    //Set socket options
    unsigned long argp = 1;
    result = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&argp, sizeof(argp));
    if (result != 0) {
        printf("Setsockopt failure: %i\n", result);
        closesocket(listenSocket);
        WSACleanup();
        return false;
    }
    //Set non blocking mode
    u_long mode = 1;
    result = ioctlsocket(listenSocket, FIONBIO, &mode);
    if (result == SOCKET_ERROR) {
        std::cerr << "Server::ioctlsocket (Make it non blocking) Failed: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return false;
    }
    //Bind address and port
    sockaddr_in serverAddr = { 0 };
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddr.sin_port = htons(port);
    result = bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
    if (result == SOCKET_ERROR) {
        std::cerr << "Server::Bind Failed: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return false;
    }
    //Set up listening
    result = listen(listenSocket, SOMAXCONN);
    if (result == SOCKET_ERROR) {
        std::cerr << "Server::listen Failed: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return false;
    }
    isRunning = true;
    return true;
}

服务器端检测客户端连接代码

struct ServerClient {
    sockaddr_in clientAddrWin;
    SOCKET clientSocketWin;
};
void Server::checkIncomingConnection() {
    fd_set readSet = { 1,{listenSocket} };
    timeval timeoutVal = { 0,0 };
    int result = select(0, &readSet, NULL, NULL, &timeoutVal);
    if (result == SOCKET_ERROR) {
        printf("Server::checkIncomingConnection Could not select: %i\n", WSAGetLastError());
        return;
    }
    else if (result == 0) {
        //printf("Server::checkIncomingConnection select timed out: %i\n", WSAGetLastError());
        return;
    }
    ServerClient incoming;
    int clientAddrLen = sizeof(incoming.clientAddrWin);
    incoming.clientSocketWin = accept(listenSocket, (sockaddr*)&incoming.clientAddrWin, &clientAddrLen);
    if (incoming.clientSocketWin == SOCKET_ERROR || incoming.clientSocketWin == INVALID_SOCKET) {
        printf("Server::checkIncomingConnection Error Accepting Client: %i\n", WSAGetLastError());
        return;
    }
    printf("Has Incoming Client\n");
    addClient(&incoming);
}

问题分析与解决

WSA错误10037对应WSAEALREADY,表示非阻塞套接字上已有一个正在进行的连接请求。你的客户端代码核心问题在于:

  1. 重复调用connect触发错误
    非阻塞模式下,第一次调用connect后连接请求已处于挂起状态,循环中再次调用connect会直接触发WSAEALREADY错误,而非等待连接完成。

  2. 非阻塞connect的处理逻辑错误
    非阻塞connect不会立即完成,正确流程是:调用connect返回WSAEWOULDBLOCK后,通过select等待套接字变为可写状态,再通过getsockopt检查连接是否成功,而非反复调用connect。

修正后的客户端连接逻辑

bool Client::connectToServer(std::string ip, int port) {
    sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    int result = inet_pton(AF_INET, ip.c_str(), &serverAddr.sin_addr);
    if (result != 1) {
        printf("Failed to convert IP address: %i\n", WSAGetLastError());
        reset();
        return false;
    }
    serverAddr.sin_port = htons(port);
    serverIp = ip;
    serverPort = port;

    // 发起非阻塞连接
    result = connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr));
    if (result == SOCKET_ERROR) {
        int error = WSAGetLastError();
        if (error != WSAEWOULDBLOCK) {
            printf("Client::Socket Error: %i\n", error);
            reset();
            return false;
        }

        // 等待连接完成(10秒超时)
        fd_set writeSet;
        FD_ZERO(&writeSet);
        FD_SET(clientSocket, &writeSet);
        timeval timeout = {10, 0};

        result = select(0, NULL, &writeSet, NULL, &timeout);
        if (result == SOCKET_ERROR) {
            printf("Client::select Error: %i\n", WSAGetLastError());
            reset();
            return false;
        } else if (result == 0) {
            printf("Client::connect Timeout\n");
            reset();
            return false;
        }

        // 检查连接是否成功
        int optVal;
        int optLen = sizeof(optVal);
        if (getsockopt(clientSocket, SOL_SOCKET, SO_ERROR, (char*)&optVal, &optLen) == SOCKET_ERROR) {
            printf("Client::getsockopt Error: %i\n", WSAGetLastError());
            reset();
            return false;
        }
        if (optVal != 0) {
            printf("Client::connect Failed: %i\n", optVal);
            reset();
            return false;
        }
    }

    isConnected = true;
    return true;
}

额外检查点

  • 确保服务器的checkIncomingConnection函数被持续循环调用,否则会错过客户端的连接请求
  • 验证客户端使用的IP和端口与服务器绑定的完全一致,避免连接到错误地址
  • 检查系统防火墙是否允许该端口的TCP通信,防止连接请求被拦截

内容的提问来源于stack exchange,提问作者BackSpace7777777

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:17:01