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

发布于 2024-07-13 20:52:16 字数 1057 浏览 3 评论 0原文

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

To simplify, this is a situation where a NamedPipe SERVER is waiting for a NamedPipe CLIENT to write to the pipe (using WriteFile())

The Windows API that is blocking is ReadFile()

The Server has created the synchronous pipe (no overlapped I/O) with blocking enabled

The client has connected, and now the server is waiting for some data.

In the normal flow of things, the client sends some data and the server processes it and then returns to ReadFile() to wait for the next chunk of data.

Meanwhile an event occurs (user input for example) and the NamedPipe SERVER must now execute some other code, which it cannot do while the ReadFile() is blocking.

At this point I need to mention that the NamedPipe Client is not my application, so I have no control over it. I cannot make it send a few bytes to unblock the server. It is just going to sit there and send no data. Since I do not have control of the Client implementation I cannot change anything on that end.

One solution would be to create a separate thread in which all ReadFile() operations are performed. That way when the event occurs, I can just process the code. The problem with that, is that the event also requires a separate thread, so now I have two additional threads for each instance of this server. Since this needs to be scalable, this is undesirable.

From another thread I have tried calling

 DisconnectNamedPipe()

and

 CloseHandle()

they both will not return (until the client writes to the pipe.)

I cannot connect to the same pipe and write a few bytes because:

"All instances of a named pipe share the same pipe name, but each instance has
its own buffers and handles, and provides a separate conduit for client/server
communication."

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

I need a way to fake it out, So the $64k dollar question is:

How can I break the blocking of ReadFile()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

我的奇迹 2024-07-20 20:52:16

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

Try this before 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-

友谊不毕业 2024-07-20 20:52:16

看一下 CancelSynchronousIo

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

和 CancelIo/CancelIoEx:

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

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

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

Take a look on CancelSynchronousIo

Marks pending synchronous I/O
operations that are issued by the
specified thread as canceled.

And CancelIo/CancelIoEx:

To cancel all pending asynchronous I/O
operations, use either:

CancelIo — this function only cancels
operations issued by the calling
thread for the specified file handle.

CancelIoEx — this function cancels all
operations issued by the threads for
the specified file handle.

ペ泪落弦音 2024-07-20 20:52:16

迈克,

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

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

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

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

Mike,

You can't cancel synchronous ReadFile. But you can switch to asynchronous (overlapped) operations. By doing this, you can implement a pretty scalable architecture.

Possible algorithm (just an idea):

  • For each new client call ReadFile
  • WaitForMultipleObjects where the handles are overlapped.hEvent + your
    custom events
  • Iterate over signalled events, and schedule them for execution by threads from a threads pool.

This way you can have only few threads to receive connections and read data, while the actual data processing can be done by the threads pool.

五里雾 2024-07-20 20:52:16

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

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

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

The problem with that, is that the
event also requires a separate thread,
so now I have two additional threads
for each instance of this server.
Since this needs to be scalable, this
is undesirable.

Never in my career have I found that "more threads" == "less scalable". How many of these "server" instances do you have?

Normally, an operation needs to be performed in a separate thread if that operation is going to block and the system needs to be responsive while the operation is blocked.

过期情话 2024-07-20 20:52:16

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

Asynchronous I/O operations do not have to block any thread if they use I/O Completion Ports. See: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

北方的巷 2024-07-20 20:52:16

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

What happening is the server outbound pipe is left open waiting for connection while your client is trying to connect to the server inbound pipe (which is no longer existent)... What you need to do is flush out your outbound pipe in order to loop back to your inbound. You can flush out on the client side by reading the file (remember to loop the connect establishment because there is a "handshake" in there, and it will never work the first time)

梦亿 2024-07-20 20:52:16

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

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

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

之后,当没有可用数据时,对ReadFile的调用将不会阻塞线程。

Just use SetNamedPipeHandleState function
https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate

Use the PIPE_NOWAIT flag when calling this function.

hNamedPipe should be the handle that returned from CreateFile function.

After that, the call to ReadFile will not block the thread when no data available.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文