我的应用程序将数据流(写)到命名管道中,在调用应用程序时将管道名称指定为CLI参数。流数据是不规则的,其中可能没有任何数据要向管道发送。
我想检测从管道读取的其他进程何时关闭它的结束,以便快速释放我的应用程序为流分配的资源。我现在的问题是甚至检测到管道的读取端已经关闭而没有在管道中写入任何东西。
由于流数据格式是固定的并且不允许空写入或ping,我不能简单地尝试写一些管道数据,即使我没有任何流来查看管道读取器是否仍在读取。
我在Linux上有一个可行的解决方案,遗憾的是它在Windows上不起作用,因为Windows命名管道不能像在Linux上那样在select()中统一处理。在Linux上,我只是检查管道的写入端是否可读,因为这表示管道错误,然后关闭管道并释放我分配的资源。
在Windows上,这是不可能的。我打开了这样写的管道:
fifo = open('//./pipe/somepipe', 'wb')
试图从管道fifo.read()
不起作用(如预期的那样)并立即抛出OSException
。
正如我所说,我不能尝试一些空/无写; fifo.write(b'')
什么都不做,甚至根本没有把管道戳成可写性。
Windows上是否有任何方法可以测试命名管道的写入结束以查看读取器(客户端)是否仍然连接?
正如@eryksun上面指出的那样,实际上可以直接使用Win32 API WriteFile
写一个探测零长度字节字符串:如果管道关闭,那么如果管道将返回“不成功”(false / 0)还活着,然后“成功”(真/!= 0)。正是我所要求的。当我发现这比使用NtQueryInformationFile
更简单时,我现在使用空写入方法;这是一个简化的例子:
import ctypes
from ctypes import byref, c_ulong, c_char_p
import msvcrt
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
fifo = open('//./pipe/somepipe', 'wb')
data = b''
written = c_ulong(0)
if not kernel32.WriteFile(
msvcrt.get_osfhandle(fifo.fileno()),
c_char_p(data), 0,
byref(written),
None):
last_error = ctypes.get_last_error()
if last_error in (
0x000000E8, # ERROR_NO_DATA
# enable as required: 0x000000E9, # ERROR_PIPE_NOT_CONNECTED
):
# pipe broken
pass
else:
# something else is wrong...
pass
else:
# pipe still okay
pass
有用的资源: