首页 > 解决方案 > 在 WSAEnumNetworkEvents 之后调用 WSAResetEvent 是否会导致事件不再被设置?

问题描述

我们有一个线程正在读取套接字。我们在一个网络上遇到了一个问题,这个问题的延迟比我们习惯的要多一些,我们的读取循环似乎会停止收到有关套接字上读取事件的通知。原始代码(删除了一些错误检查):

HANDLE hEventSocket = WSACreateEvent();
WSAEventSelect(pIOParams->sock, hEventSocket, FD_READ | FD_CLOSE);
std::array<HANDLE, 2>   ahEvents;

// This is an event handle that can be called from another thread to 
// get this read thread to exit
ahEvents[0] = pIOParams->hEventStop; 
ahEvents[1] = hEventSocket;
while(pIOParams->bIsReading)
{
    // wait for stop or I/O events
    DWORD dwTimeout = 30000; // in ms
    dwWaitResult = WSAWaitForMultipleEvents(ahEvents.size(), ahEvents.data(), FALSE, dwTimeout, FALSE);
    if(dwWaitResult == WSA_WAIT_TIMEOUT)
    {
        CLogger::LogPrintf(LogLevel::LOG_DEBUG, "CSessionClient", "WSAWaitForMultipleEvents time out");
        continue;  
    }
    if(dwWaitResult == WAIT_OBJECT_0) // check to see if we were signaled to stop from another thread
    {
         break;
    }
    if(dwWaitResult == WAIT_OBJECT_0 +1)
    {
        // determine which I/O operation triggered event
        if (WSAEnumNetworkEvents(pIOParams->sock, hEventSocket, &NetworkEvents) != 0)
        {
            int err = WSAGetLastError();
            CLogger::LogPrintf(LogLevel::LOG_WARN, "CSessionClient", "WSAEnumNetworkEvents failed (%d)", err);
            break;
        }

        // HERE IS THE LINE WE REMOVED THAT SEEMED TO FIX THE PROBLEM
        WSAResetEvent(hEventSocket);

        // Handle events on socket
        if (NetworkEvents.lNetworkEvents & FD_READ)
        {
             // Do stuff to read from socket
        }
        if (NetworkEvents.lNetworkEvents & FD_CLOSE)
        {
             // Handle that the socket was closed
             break;
        }
    }

}

这是问题所在:WSAResetEvent(hEventSocket);在代码中,有时程序可以工作并从服务器读取所有数据,但有时,它似乎卡在接收 WSA_WAIT_TIMEOUT 的循环中,即使服务器似乎有数据排队等待它.

当程序循环接收 WSA_WAIT_TIMEOUT 时,Process Hacker显示套接字连接处于正常状态。

现在我们知道这WSAEnumNetworkEvents将重置 hEventSocket,但额外的调用似乎不会WSAResetEvent受到伤害。它也没有任何意义,它会永久地扰乱信号。我希望我们可能不会收到要读取的最后一块数据的通知,因为在调用WSAEnumNetworkEventsand之间可能已经读取了数据WSAResetEvent,但是我假设一旦套接字上有额外的数据进入hEventSocket,得到提升。

奇怪的是,我们多年来一直在运行此代码,而我们现在才看到这个问题。

任何想法为什么这会导致问题?

标签: c++cwinsockwinsock2

解决方案


您已经将事件句柄传递给 WSAEnumNetworkEvents,它以原子方式重置句柄。也就是说,只有在复制挂起的事件数据时才会重置句柄。

通过直接调用 WSAResetEvent,可能会丢失数据通知(即您调用 WSAEnumNetworkEvents 以获取当前状态并重置事件,之后更多数据到达导致事件被设置但在调用 WSAResetEvent 之前,您然后在下一次循环迭代之前调用 WSAResetEvent ,除非有更多数据进入,否则您不会被告知已经进入的数据)。

让 WSAEnumNetworkEvents 处理事件状态要好得多。


推荐阅读