[英]Breaking ReadFile() blocking - Named Pipe (Windows API)
为简化起见,这是一种 NamedPipe SERVER 正在等待 NamedPipe CLIENT 写入管道的情况(使用 WriteFile())
阻塞的 Windows API 是 ReadFile()
服务器已创建启用阻塞的同步管道(无重叠 I/O)
客户端已连接,现在服务器正在等待一些数据。
在正常的事物流中,客户端发送一些数据,服务器处理它,然后返回 ReadFile() 等待下一个数据块。
同时发生一个事件(例如用户输入),NamedPipe SERVER 现在必须执行一些其他代码,而 ReadFile() 阻塞时它无法执行此操作。
在这一点上我需要提到 NamedPipe Client 不是我的应用程序,所以我无法控制它。 我不能让它发送几个字节来解锁服务器。 它只是坐在那里不发送数据。 由于我无法控制客户端实现,因此我无法更改任何内容。
一种解决方案是创建一个单独的线程,在其中执行所有 ReadFile() 操作。 这样当事件发生时,我可以只处理代码。 问题是该事件还需要一个单独的线程,所以现在我为该服务器的每个实例都有两个额外的线程。 由于这需要可扩展,因此这是不可取的。
从另一个线程我尝试调用
DisconnectNamedPipe()
和
CloseHandle()
它们都不会返回(直到客户端写入管道。)
我无法连接到同一个管道并写入几个字节,因为:
“命名管道的所有实例共享相同的管道名称,但每个实例都有自己的缓冲区和句柄,并为客户端/服务器通信提供单独的管道。”
http://msdn.microsoft.com/en-us/library/aa365590.aspx
我需要一种方法来伪造它,所以 64,000 美元的问题是:
如何打破 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。 但是您可以切换到异步(重叠)操作。 通过这样做,您可以实现一个非常可扩展的架构。
可能的算法(只是一个想法):
这样你就可以只有很少的线程来接收连接和读取数据,而实际的数据处理可以由线程池完成。
问题是该事件还需要一个单独的线程,所以现在我为该服务器的每个实例都有两个额外的线程。 由于这需要可扩展,因此这是不可取的。
在我的职业生涯中,我从未发现“更多线程”==“可扩展性较差”。 你有多少这样的“服务器”实例?
通常,如果该操作将被阻塞并且系统需要在该操作被阻塞时做出响应,则该操作需要在单独的线程中执行。
发生的事情是当您的客户端尝试连接到服务器入站管道(不再存在)时,服务器出站管道处于打开状态等待连接......您需要做的是冲洗出站管道以便循环回到您的入站。 您可以通过读取文件在客户端刷新(记住循环连接建立,因为那里有“握手”,它永远不会第一次工作)
如果异步 I/O 操作使用 I/O 完成端口,则不必阻塞任何线程。 请参阅: http : //msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx
只需使用SetNamedPipeHandleState
函数https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate
调用此函数时使用PIPE_NOWAIT
标志。
hNamedPipe
应该是从CreateFile
函数返回的句柄。
之后,当没有可用数据时,对ReadFile
的调用将不会阻塞线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.