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

C++ Socket服务器处理一次连接后无提示关闭,求故障原因

Socket服务器单次通信后异常关闭问题分析与解决

我正在用C++开发一个Socket服务器,接受连接后创建线程向连接发送数据,但每次运行服务器时,向一个用户发送一次数据后就直接关闭,且无错误提示。相关代码如下:

主循环代码

while (TRUE){
    listen_sock = listen(sock, SOMAXCONN);
    if (listen_sock == 0){
        accept_sock = accept(sock, NULL, NULL);
        if(accept_sock == INVALID_SOCKET){ 
            cout << "part 5\n";
            printf("accepting connection failed with error: %d\n", WSAGetLastError());
        }
        thread thrd(send_dat, accept_sock);
        thrd.detach();
    }
    else if (listen_sock == SOCKET_ERROR){
        cout << "part 4\n";
        printf("\n\nlistening on socket failed with error: %d\n", WSAGetLastError());
    }
}

数据处理线程函数

void send_dat(SOCKET accept_sock){
/*variable declarations here*/
data = recv(accept_sock, recvbuf, recvbuflen, 0);
if (data == SOCKET_ERROR){
    cout << "part -1\n";
    throw runtime_error("Failed to receive data");
    WSAGetLastError();
}
data_res = response(data);
send_sock = send(accept_sock, data_res_len, data_res, 0);
if (send_sock == SOCKET_ERROR){
    cout << "part -2\n";
    throw runtime_error("Failed to send data");
    WSAGetLastError();
}
}

问题原因分析

  • listen函数滥用:listen仅需调用一次,用于将套接字切换为监听状态。你在循环中反复调用它,第一次成功后后续调用会返回SOCKET_ERROR(错误码WSAEINVAL),导致逻辑异常;且accept应在listen成功后循环调用,而非每次循环先执行listen。
  • 未捕获异常导致进程终止:分离的线程(detach())中抛出未捕获的runtime_error会直接终止整个进程,这是服务器无提示关闭的核心原因。另外throw后的WSAGetLastError()永远不会执行,无法获取错误码。
  • send参数顺序错误:send的正确参数是(套接字, 数据缓冲区, 数据长度, 标志),你颠倒了缓冲区和长度的位置,必然导致send调用失败触发异常。
  • 未处理客户端正常断开:recv返回0表示客户端主动断开,你的代码未处理该情况,会进入后续错误逻辑。

修复后的代码示例

主循环修正

// 仅调用一次listen,初始化监听状态
listen_sock = listen(sock, SOMAXCONN);
if (listen_sock == SOCKET_ERROR){
    cout << "part 4\n";
    printf("\n\nlistening on socket failed with error: %d\n", WSAGetLastError());
    return; // 监听失败直接退出
}

// 循环接受客户端连接
while (TRUE){
    accept_sock = accept(sock, NULL, NULL);
    if(accept_sock == INVALID_SOCKET){ 
        cout << "part 5\n";
        int err = WSAGetLastError();
        printf("accepting connection failed with error: %d\n", err);
        continue; // 接受失败,继续等待下一个连接
    }
    thread thrd(send_dat, accept_sock);
    thrd.detach();
}

数据处理线程修正

void send_dat(SOCKET accept_sock){
    try {
        int data_len = recv(accept_sock, recvbuf, recvbuflen, 0);
        if (data_len == SOCKET_ERROR){
            cout << "part -1\n";
            int err = WSAGetLastError();
            printf("recv failed with error: %d\n", err);
            closesocket(accept_sock);
            return;
        }
        else if (data_len == 0){
            cout << "Client disconnected normally\n";
            closesocket(accept_sock);
            return;
        }

        // 假设response函数接收数据长度和缓冲区,返回处理后的数据及长度
        // 请根据实际实现调整response的调用方式
        char* data_res = nullptr;
        int data_res_len = 0;
        tie(data_res, data_res_len) = response(data_len, recvbuf);

        int send_result = send(accept_sock, data_res, data_res_len, 0);
        if (send_result == SOCKET_ERROR){
            cout << "part -2\n";
            int err = WSAGetLastError();
            printf("send failed with error: %d\n", err);
            closesocket(accept_sock);
            // 释放data_res内存(如果response分配了堆内存)
            delete[] data_res;
            return;
        }

        // 释放资源
        delete[] data_res;
        closesocket(accept_sock);
    }
    catch (const exception& e){
        cout << "Thread exception: " << e.what() << "\n";
        closesocket(accept_sock);
    }
}

额外注意事项

  • 所有套接字使用完毕后必须调用closesocket关闭,避免资源泄漏。
  • 分离线程必须捕获所有异常,禁止未捕获异常导致进程崩溃。
  • 确认response函数的内存管理逻辑,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:05:21