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,表示非阻塞套接字上已有一个正在进行的连接请求。你的客户端代码核心问题在于:
重复调用
connect触发错误
非阻塞模式下,第一次调用connect后连接请求已处于挂起状态,循环中再次调用connect会直接触发WSAEALREADY错误,而非等待连接完成。非阻塞
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
相关产品推荐
相关产品推荐

