C++ Winsock接受事件有时会停止发送信号(WSAEventSelect)

C++ Winsock接受事件有时会停止发送信号(WSAEventSelect),c++,windows,events,winsock,C++,Windows,Events,Winsock,我对作为多线程套接字服务器一部分的一段遗留c++/winsock代码有一个问题。应用程序创建一个线程来处理来自客户机的连接,其中通常有数百个在任何时间连接。它通常连续几天无故障运行,然后突然停止接受连接。这只发生在生产中,从不测试 它使用WSAEventSelect检测FD_接受网络事件。连接处理程序的简化代码为: SOCKET listener; HANDLE hStopEvent; // ... initialise listener and hStopEvent, and other s

我对作为多线程套接字服务器一部分的一段遗留c++/winsock代码有一个问题。应用程序创建一个线程来处理来自客户机的连接,其中通常有数百个在任何时间连接。它通常连续几天无故障运行,然后突然停止接受连接。这只发生在生产中,从不测试

它使用WSAEventSelect检测FD_接受网络事件。连接处理程序的简化代码为:

SOCKET listener;
HANDLE hStopEvent;

// ... initialise listener and hStopEvent, and other stuff ...

HANDLE hAcceptEvent = WSACreateEvent();
WSAEventSelect(listener, hAcceptEvent, FD_ACCEPT); 
HANDLE rghEvents[] = { hStopEvent, hAcceptEvent };

bool bExit = false;
while(!bExit)
{
    DWORD nEvent = WaitForMultipleObjects(2, rghEvents, FALSE, INFINITE);
    switch(nEvent)
    {
        case WAIT_OBJECT_0:
            bExit = true;
            break;
        case WAIT_OBJECT_1:
            HandleConnect();
            WSAResetEvent(hAcceptEvent);
            break;
        case WAIT_ABANDONED_0:
        case WAIT_ABANDONED_0 + 1:
        case WAIT_FAILED:
            LogError();
            break;
    }
}
从详细的日志记录中,我知道,当问题发生时,线程进入WaitForMultipleObjects,并且永远不会出现,即使有客户端试图连接并等待接受。等待失败,等待放弃的情况从未发生

虽然我还没有排除服务器上的配置问题,或者甚至某种资源泄漏找不到任何东西,但我还想知道WSACreateEvent创建的事件是否与FD_ACCEPT网络事件“解除关联”——导致它永远不会触发

那么,我是不是做错了什么?有什么我不应该做的事吗?还是更好的方法?如果有任何建议,我将不胜感激!谢谢

编辑

该插座为非阻塞插座

编辑


使用下面kipkennedy建议的方法解决问题。将HAccepteEvent更改为自动重置事件,并删除了不再需要的对WSAResetEvent的调用。

代码看起来不错。我唯一能建议的是调用,而不是全局版本。

代码看起来不错。我唯一能建议的是调用而不是全局版本。

从阅读中可以看出,WSAEventSelect在通知方面与WSAAsyncSelect一样吝啬。堆栈不会在每次连接时发出FD_ACCEPT信号。对于Winsock来说,通知是其表达方式:

您之前调用了accept,但由于WSAEWOULDBLOCK而失败。继续,再打一次电话,这次应该会成功

解决方案是在调用WSAEventSelect之前调用accept,只有在获得WSAEWOULDBLOCK之后才调用WSAEventSelect。要使其按预期工作,您需要将侦听套接字设置为非阻塞。这似乎很明显,但实际上并不是必需的。

从阅读中可以看出,WSAEventSelect在通知方面似乎与WSAAsyncSelect一样吝啬。堆栈不会在每次连接时发出FD_ACCEPT信号。对于Winsock来说,通知是其表达方式:

您之前调用了accept,但由于WSAEWOULDBLOCK而失败。继续,再打一次电话,这次应该会成功


解决方案是在调用WSAEventSelect之前调用accept,只有在获得WSAEWOULDBLOCK之后才调用WSAEventSelect。要使其按预期工作,您需要将侦听套接字设置为非阻塞。这可能看起来很明显,但实际上并不需要。

可能FD_ACCEPT在HandleConnect过程中在ACCEPT之后、return和随后的reset事件之前发出信号。然后,ResetEvent将重置所有信号,并且不会调用重新启用accept。例如,以下顺序是可能的:

发出事件信号,WaitForMultipleObjects返回 在HandleConnect期间,在调用accept之后的某个时间,事件会再次发出信号 HandleConnect返回 ResetEvent重置事件,屏蔽第二个信号 WaitForMultipleObjects永远不会返回,因为就Windows而言,它已经发出后续事件的信号,并且没有后续接受重新启用它
两种可能的解决方案:1在HandleConnect中循环accept,直到返回WSAEWOULDBLOCK;2使用自动重置事件或在调用HandleConnect之前立即重置事件可能FD_accept在HandleConnect过程中在accept之后、返回和后续重置事件之前发出信号。然后,ResetEvent将重置所有信号,并且不会调用重新启用accept。例如,以下顺序是可能的:

发出事件信号,WaitForMultipleObjects返回 在HandleConnect期间,在调用accept之后的某个时间,事件会再次发出信号 HandleConnect返回 ResetEvent重置事件,屏蔽第二个信号 WaitForMultipleObjects永远不会返回,因为就Windows而言,它已经发出后续事件的信号,并且没有后续接受重新启用它
两种可能的解决方案:1在HandleConnect中循环accept,直到返回WSAEWOULDBLOCK;2使用自动重置事件或在调用HandleConnect之前立即重置事件发生accept事件后,不得执行WSARestEventThAccepteven。您必须发出WSAEnumNetworkEvents侦听器、hAcceptEvent和some_结构。此函数用于清除套接字的内部状态,并将此状态复制到某些结构中,然后您可以接收新连接。

发生接受事件后
红色:您不能执行WSAResetEventhAcceptEven。您必须发出WSAEnumNetworkEvents侦听器、hAcceptEvent和some_结构。此函数用于清除套接字的内部状态,并将此状态复制到某个结构中,然后您可以接收新连接。

看起来WSWaitForMultipleObjects只是WaitForMultipleObjects的包装器,所以我不确定这是问题所在。不过我很感激你的建议,John。看起来WSAWaitForMultipleObjects只是WaitForMultipleObjects的包装器,所以我不确定这是不是问题所在。我很感激你的建议,约翰。沃伦-谢谢你花时间回复。我应该说插座是非阻塞的。发布的代码可以正常工作几天,响应所有连接尝试,然后在任何客户端尝试连接时突然停止向事件发送信号。我开始怀疑服务器上有配置问题,或者资源泄漏。Warren-感谢您花时间回复。我应该说插座是非阻塞的。发布的代码可以正常工作几天,响应所有连接尝试,然后在任何客户端尝试连接时突然停止向事件发送信号。我开始怀疑服务器上存在配置问题,或者资源泄漏。我终于有时间尝试你的建议,并且似乎已经解决了问题。非常感谢你的帮助!作为记录,我将代码更改为使用自动重置事件,如您文章中第二个解决方案中所述。我终于有时间尝试您的建议,似乎解决了问题。非常感谢你的帮助!作为记录,我更改了代码以使用自动重置事件,如您文章中第二个解决方案中所述。