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 后服务器崩溃的主要内容,如果未能解决你的问题,请参考以下文章
Windows 中对套接字的 closesocket() 调用需要 20 秒 [关闭]