WSAEventSelect标记就绪后,ReadFile仍发生挂起的场景有哪些?
安全扫描软件触发的TCP套接字挂起问题分析
这一问题颇为棘手。我们遇到了由某款安全扫描软件引发(确切说是触发)的异常挂起情况。怀疑该软件采用了非标准TCP/IP栈,客户正询问挂起原因。
静态分析显示挂起仅可能出现在两个位置:套接字的ReadFile()或WriteFile()操作中;除非扫描软件故意将窗口大小设为0,否则WriteFile()不会在此处挂起。即便WriteFile()未取得进展但能返回,我也能解除程序的阻塞状态,且日志状态也与WriteFile()返回的情况不符。
接下来分析ReadFile(),以下是调用序列:
SOCKET conn; HANDLE unwedgeEvent = CreateEvent(NULL, TRUE, FALSE, NULL); HANDLE listenEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (listenEvent == NULL) return; //... conn = accept(lstn); for (;;) { HANDLE wakeup[2]; wakeup[0] = unwedgeEvent; wakeup[1] = listenEvent; if (WSAEventSelect(conn, socket, FD_READ | FD_CLOSE) == 0) { // Log error break; } which = WaitForMultipleObjects(2, wakeup, FALSE, INFINITE); if (which < 0) { // Log error break; } if (which == 1) { DWORD read; r = ReadFile(conn, chunk, 4096, &read, NULL); if (r == 0) { // Handle error -- not stuck here } else { // Handle data -- not stuck here either } } if (which == 0) break; }
在此场景下,触发unwedgeEvent无法起到任何作用,线程会永久阻塞。
所以我真正的疑问是:这真的可能发生,还是我搞错了?
目前问题已陷入僵局;我完全不需要非阻塞套接字,只需要一个能同时处理套接字和非套接字句柄的select()函数。
以下API调用序列不会导致ReadFile挂起:
--------------------------------------------------------------- Sender B Receiver WSAEventSelect * WaitForMultipeObjects send(buffer size = 1) ReadFile(size = 1) WSAEventSelect * WaitForMultipeObjects send(buffer size = 1) ReadFile(size = 1) ................................................................ WSAEventSelect * WaitForMultipeObjects send(buffer size = 2) ReadFile(size = 1) WaitForMultipeObjects ReadFile(size = 1) ................................................................ WSAEventSelect * WaitForMultipeObjects send(buffer size = 1) send(buffer size = 1) ReadFile(size = 1) WaitForMultipeObjects ReadFile(size = 1) ................................................................ WSAEventSelect send(buffer size = 1) WaitForMultipeObjects send(buffer size = 1) ReadFile(size = 1) WaitForMultipeObjects ReadFile(size = 1) ................................................................ WSAEventSelect send(buffer size = 1) WaitForMultipeObjects send(buffer size = 1) ReadFile(size = 2) * WaitForMultipeObjects send(buffer size = 1) ReadFile(size = 1) ................................................................ WSAEventSelect send(buffer size = 1) WaitForMultipeObjects ReadFile(size = 1) send(buffer size = 1) WaitForMultipeObjects ReadFile(size = 1)
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

