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

为简化起见,这是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()的阻塞?

在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-

看看CancelSynchronousIo

将指定线程发出的待处理同步I / O操作标记为已取消。

和CancelIo / CancelIoEx:

要取消所有挂起的异步I / O操作,请使用以下任一操作:

CancelIo – 此函数仅取消调用线程为指定文件句柄发出的操作。

CancelIoEx – 此函数取消线程为指定文件句柄发出的所有操作。

麦克风,

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

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

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

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

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

从来没有在我的职业生涯中发现“更multithreading”==“可扩展性更低”。 你有多少这些“服务器”实例?

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

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

当您的客户端尝试连接到服务器入站管道(不再存在)时,服务器出站管道保持打开状态等待连接… …您需要做的是清除出站管道以便循环回到你的入境。 你可以通过读取文件在客户端刷新(记得循环连接建立,因为那里有一个“握手”,它将永远不会工作)