打破ReadFile()阻塞 - 命名管道(Windows API)

时间:2009-02-27 01:07:02

标签: c++ c winapi named-pipes

为简化起见,这是NamedPipe SERVER正在等待NamedPipe CLIENT写入管道的情况(使用WriteFile())

阻止的Windows API是ReadFile()

服务器已创建同步管道(无重叠I / O)并启用了阻止

客户端已连接,现在服务器正在等待一些数据。

在正常的事物流中,客户端发送一些数据,服务器处理它,然后返回ReadFile()等待下一个数据块。

同时发生一个事件(例如用户输入),并且NamedPipe SERVER现在必须执行一些其他代码,当ReadFile()阻塞时,它不能执行。

此时我需要提一下,NamedPipe客户端不是我的应用程序,所以我无法控制它。我不能让它发送几个字节来解锁服务器。它只是坐在那里,不发送数据。由于我无法控制客户端实现,因此我无法更改任何内容。

一种解决方案是创建一个单独的线程,其中执行所有ReadFile()操作。这样,当事件发生时,我可以只处理代码。问题在于,事件还需要一个单独的线程,所以现在我为这个服务器的每个实例都有两个额外的线程。由于这需要可扩展,这是不可取的。

我试过调用

的另一个帖子
 DisconnectNamedPipe()

 CloseHandle()

它们都不会返回(直到客户端写入管道。)

我无法连接到同一个管道并写入几个字节,因为:

“命名管道的所有实例共享相同的管道名称,但每个实例都有 它自己的缓冲区和句柄,并为客户端/服务器提供单独的管道 通信“。

http://msdn.microsoft.com/en-us/library/aa365590.aspx

我需要一种方法来伪造它,所以$ 64k美元的问题是:

如何打破ReadFile()的阻塞?

7 个答案:

答案 0 :(得分:14)

在ReadFile之前尝试这个:

BOOL WINAPI PeekNamedPipe(
  __in       HANDLE hNamedPipe,
  __out_opt  LPVOID lpBuffer,
  __in       DWORD nBufferSize,
  __out_opt  LPDWORD lpBytesRead,
  __out_opt  LPDWORD lpTotalBytesAvail,
  __out_opt  LPDWORD lpBytesLeftThisMessage
);

if(TotalBytesAvail > 0)
  ReadFile(....);

-AV -

答案 1 :(得分:6)

看看CancelSynchronousIo

  

标记待处理的同步I / O.   由...发布的操作   指定的线程被取消。

和CancelIo / CancelIoEx:

  

取消所有挂起的异步I / O.   操作,使用:

     

CancelIo - 此功能仅取消   呼叫发出的操作   指定文件句柄的线程。

     

CancelIoEx - 此功能取消全部   线程发出的操作   指定的文件句柄。

答案 2 :(得分:3)

麦克,

您无法取消同步ReadFile。但是您可以切换到异步(重叠)操作。通过这样做,您可以实现可扩展的架构。

可能的算法(只是一个想法):

  • 为每个新客户调用ReadFile
  • WaitForMultipleObjects,句柄重叠.HEvent +你的 自定义活动
  • 迭代发出信号的事件,并安排它们由线程池中的线程执行。

这样,只有少数线程可以接收连接和读取数据,而实际的数据处理可以由线程池完成。

答案 3 :(得分:2)

  

问题在于,是   事件还需要一个单独的线程,   所以现在我有两个额外的线程   对于此服务器的每个实例。   由于这需要可扩展,这个   是不受欢迎的。

在我的职业生涯中,我从未发现“更多线程”==“可扩展性更低”。你有多少个“服务器”实例?

通常情况下,操作需要在单独的线程中执行,如果该操作将被阻止,并且系统需要在操作被阻止时响应。

答案 4 :(得分:1)

如果异步I / O操作使用I / O完成端口,则不必阻止任何线程。请参阅:http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

答案 5 :(得分:1)

当您的客户端尝试连接到服务器入站管道(不再存在)时,服务器出站管道保持打开等待连接的情况... ...您需要做的是清除出站管道为了循环回你的入境。您可以通过读取文件来清除客户端(请记住循环连接建立,因为那里存在"握手"并且它将永远不会在第一次工作)

答案 6 :(得分:0)

只需使用SetNamedPipeHandleState函数 https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate

调用此函数时,请使用PIPE_NOWAIT标志。

hNamedPipe应该是CreateFile函数返回的句柄。

此后,在无可用数据时,对ReadFile的调用将不会阻塞线程。