closesocket 后服务器崩溃

Posted

技术标签:

【中文标题】closesocket 后服务器崩溃【英文标题】:Server crashes after closesocket 【发布时间】:2017-02-18 18:45:33 【问题描述】:

我有多线程应用程序,它定期轮询数百个设备。 每个线程为一个设备服务,它的套接字和其他描述符被封装在单独的对象中,因此没有共享描述符。 当我尝试将描述符 fSock 设置为 0 时,有时应用程序在 closesocket(fSock) 后崩溃。

我假设,如果 closesocket(fSock) 返回 SOCKET_ERROR,我不应该设置 fSock = 0。 还是有其他原因?

我的代码:

bool _EthDev::Connect()

    int sockErr, ret, i, j;
    int szOut = sizeof(sockaddr_in);

    // create socket
    if ((fSock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
    
        sockErr = GetLastError();
        Log("Invalid socket err %d", sockErr);
        fSock = 0;
        return false;
    

    // set fast closing socket (by RST)
    linger sLinger;
    sLinger.l_onoff = 1;
    sLinger.l_linger = 0;
    if (sockErr = setsockopt(fSock, SOL_SOCKET, SO_LINGER, (const char FAR*)&sLinger, sizeof(linger)))
    
        sockErr = WSAGetLastError();
        Log("Setsockopt err %d", sockErr);
        closesocket(fSock);
        fSock = 0;          // here crashes
        return false;
    

    // connect to device
    fSockaddr.sin_port = htons((u_short)(baseport));
    if (connect(fSock, (struct sockaddr*)&fSockaddr, szOut))
    
        closesocket(fSock);
        fSock = 0;
        return false;
    

    ...

    return true;

【问题讨论】:

零不是套接字的无效值。如果您想指示 fSock 不再是有效套接字,则应将其设置为 INVALID_SOCKET 而不是 0,因为根据定义,INVALID_SOCKET 是一个永远不会被有效套接字使用的值。 【参考方案1】:

我有多线程应用程序,... [它] 偶尔会崩溃

偶尔崩溃的多线程应用程序是竞争条件的典型症状。我认为为了防止崩溃,您需要弄清楚代码中的竞争条件,然后修复它。

我假设,如果 closesocket(fSock) 返回,我不应该设置 fSock = 0 SOCKET_ERROR。还是有其他原因?

我怀疑这个问题实际上与 closesocket() 或将 fSock 设置为 0 有关。请记住,套接字实际上只是整数,将整数设置为 0 本身不太可能导致崩溃。 可能导致崩溃的是对无效内存的写入 - 而fSock = 0 确实会写入成员变量fSock 所在(或曾经)所在的内存位置。

因此,一个更可能的假设是线程 B 删除了 _EthDev 对象,而线程 A 仍在对其调用 Connect()。这很可能在执行 connect() 调用时发生,因为阻塞的 connect() 调用可能需要相对较长的时间才能返回。因此,如果有另一个线程在 connect() 调用期间粗鲁地删除了 _EthDev 对象,那么一旦 connect() 返回,下一行代码将写入(现已删除的)_EthDev 对象使用的位置将是“fSock = 0;”行,这可能会导致崩溃。

我建议您查看删除 _EthDev 对象的代码,如果不小心先关闭使用这些对象的任何线程(并等待线程退出!),然后再删除 _EthDev 对象,您应该重写它,使其可靠地运行。在另一个线程可能仍在使用它时删除一个对象是自找麻烦。

【讨论】:

谢谢杰里米!实际上,我在应用程序启动时创建对象并启动线程,并在退出前停止线程并删除对象。但现在我认为问题更多在于多线程而不是套接字。

以上是关于closesocket 后服务器崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Winsock编程基础2(UDP流程)

网络编程socket

有经验的程序员对 closesocket() 的担忧

Windows 中对套接字的 closesocket() 调用需要 20 秒 [关闭]

微信小程序关闭WebSocket连接wx.closeSocket()

socket中shutdown和closesocket的区别