c++ - 在 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
受到伤害。它也没有任何意义,它会永久地扰乱信号。我希望我们可能不会收到要读取的最后一块数据的通知,因为在调用WSAEnumNetworkEvents
and之间可能已经读取了数据WSAResetEvent
,但是我假设一旦套接字上有额外的数据进入hEventSocket
,得到提升。
奇怪的是,我们多年来一直在运行此代码,而我们现在才看到这个问题。
任何想法为什么这会导致问题?
解决方案
您已经将事件句柄传递给 WSAEnumNetworkEvents,它以原子方式重置句柄。也就是说,只有在复制挂起的事件数据时才会重置句柄。
通过直接调用 WSAResetEvent,可能会丢失数据通知(即您调用 WSAEnumNetworkEvents 以获取当前状态并重置事件,之后更多数据到达导致事件被设置但在调用 WSAResetEvent 之前,您然后在下一次循环迭代之前调用 WSAResetEvent ,除非有更多数据进入,否则您不会被告知已经进入的数据)。
让 WSAEnumNetworkEvents 处理事件状态要好得多。
推荐阅读
- javascript - 为什么语句 `0 < 0.5 < 1` 会减少为假?
- eclipse - Eclipse 错误无法解析为类型
- html - 没有得到正确的CSS
- python - 在 Python 中,如何删除特定字符周围的字符?
- ios - 是否可以从 iOS 6 样式收据数据中检索 iOS 7 样式收据?
- linux - 使用过滤器创建具有进程名称的文件
- java - ForEach 行动起来
- mysql - 如何在 Rails 中将 MySQL 迁移到 PostgreSQL
- java - 使用 ThymeLeaf 和 Spring MVC 动态填充模式的问题
- java - 初始化用户选择。如果我将其设置为零,我的程序将编译