为什么 os.path.exists() 会阻止 windows 命名管道连接?
Why does os.path.exists() stop windows named pipes from connecting?
似乎使用 os.path.exists()
成功测试了 windows 命名管道是否存在,从而阻止了管道的工作。为什么会这样?
此处已成功运行 windows 命名管道代码:
import time
import multiprocessing as mp
import win32pipe, win32file
PIPENAME = r'\.\pipe\Foo'
def producer(pipe_name: str):
print('producer')
# if not os.path.exists(pipe_name):
# print(f'No pipe {pipe_name}')
# return
pipe = win32file.CreateFile(pipe_name,
win32file.GENERIC_READ | win32file.GENERIC_WRITE, # dwDesiredAccess
0, # dwShareMode
None, # lpSecurityAttributes
win32file.OPEN_EXISTING, # dwCreationDisposition
0, # dwFlagsAndAttributes
None
)
win32pipe.SetNamedPipeHandleState(pipe, win32pipe.PIPE_READMODE_MESSAGE, None, None)
win32file.WriteFile(pipe, b'foobar')
def receiver(pipe_name: str):
print('receiver')
pipe = win32pipe.CreateNamedPipe(pipe_name,
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1, # nMaxInstances
65536, # nOutBufferSize
65536, # nInBufferSize
0, # 50ms timeout (the default)
None) # securityAttributes
win32pipe.ConnectNamedPipe(pipe)
msg = win32file.ReadFile(pipe, 65536)
print(f'msg: {msg}')
if __name__ == '__main__':
recv_p = mp.Process(target=receiver, args=(PIPENAME,))
prod_p = mp.Process(target=producer, args=(PIPENAME,))
recv_p.start()
time.sleep(0.1)
prod_p.start()
prod_p.join()
recv_p.join()
这按预期工作,接收方打印收到的消息。
但是如果生产者中的三个注释行未被注释,os.path.exists(pipe_name)
调用会以某种方式破坏管道,因此输出变为:
receiver
producer
Process Process-2:
Process Process-1:
Traceback (most recent call last):
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 297, in _bootstrap
self.run()
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "C:\git\redacted\named_pipe_mqtt_test.py", line 18, in producer
None
pywintypes.error: (231, 'CreateFile', 'All pipe instances are busy.')
Traceback (most recent call last):
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 297, in _bootstrap
self.run()
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "C:\git\redacted\named_pipe_mqtt_test.py", line 35, in receiver
msg = win32file.ReadFile(pipe, 65536)
pywintypes.error: (109, 'ReadFile', 'The pipe has been ended.')
为什么 os.path.exists
会破坏 windows 命名管道?
我已经排除了 python 多处理库。我在 os.path.exists
.
之后尝试过延迟
这对我来说不是阻塞问题,但我很好奇。
os.path.exists
委托给 os.stat
,在 Windows,os.stat
尝试 open 文件:
hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flags, NULL);
然后关闭文件。此时,客户端无法重新打开管道,除非服务器端先调用 DisconnectNamedPipe
,这在这段代码中不会发生。此外,当服务器端尝试从管道读取时,它正在读取 os.stat
的连接尝试,它关闭了管道而不写入任何数据。
我会认为这是一个错误。 os.stat
不应该有这样的副作用。
似乎使用 os.path.exists()
成功测试了 windows 命名管道是否存在,从而阻止了管道的工作。为什么会这样?
此处已成功运行 windows 命名管道代码:
import time
import multiprocessing as mp
import win32pipe, win32file
PIPENAME = r'\.\pipe\Foo'
def producer(pipe_name: str):
print('producer')
# if not os.path.exists(pipe_name):
# print(f'No pipe {pipe_name}')
# return
pipe = win32file.CreateFile(pipe_name,
win32file.GENERIC_READ | win32file.GENERIC_WRITE, # dwDesiredAccess
0, # dwShareMode
None, # lpSecurityAttributes
win32file.OPEN_EXISTING, # dwCreationDisposition
0, # dwFlagsAndAttributes
None
)
win32pipe.SetNamedPipeHandleState(pipe, win32pipe.PIPE_READMODE_MESSAGE, None, None)
win32file.WriteFile(pipe, b'foobar')
def receiver(pipe_name: str):
print('receiver')
pipe = win32pipe.CreateNamedPipe(pipe_name,
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1, # nMaxInstances
65536, # nOutBufferSize
65536, # nInBufferSize
0, # 50ms timeout (the default)
None) # securityAttributes
win32pipe.ConnectNamedPipe(pipe)
msg = win32file.ReadFile(pipe, 65536)
print(f'msg: {msg}')
if __name__ == '__main__':
recv_p = mp.Process(target=receiver, args=(PIPENAME,))
prod_p = mp.Process(target=producer, args=(PIPENAME,))
recv_p.start()
time.sleep(0.1)
prod_p.start()
prod_p.join()
recv_p.join()
这按预期工作,接收方打印收到的消息。
但是如果生产者中的三个注释行未被注释,os.path.exists(pipe_name)
调用会以某种方式破坏管道,因此输出变为:
receiver
producer
Process Process-2:
Process Process-1:
Traceback (most recent call last):
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 297, in _bootstrap
self.run()
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "C:\git\redacted\named_pipe_mqtt_test.py", line 18, in producer
None
pywintypes.error: (231, 'CreateFile', 'All pipe instances are busy.')
Traceback (most recent call last):
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 297, in _bootstrap
self.run()
File "C:\Users\redacted\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "C:\git\redacted\named_pipe_mqtt_test.py", line 35, in receiver
msg = win32file.ReadFile(pipe, 65536)
pywintypes.error: (109, 'ReadFile', 'The pipe has been ended.')
为什么 os.path.exists
会破坏 windows 命名管道?
我已经排除了 python 多处理库。我在 os.path.exists
.
这对我来说不是阻塞问题,但我很好奇。
os.path.exists
委托给 os.stat
,在 Windows,os.stat
尝试 open 文件:
hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flags, NULL);
然后关闭文件。此时,客户端无法重新打开管道,除非服务器端先调用 DisconnectNamedPipe
,这在这段代码中不会发生。此外,当服务器端尝试从管道读取时,它正在读取 os.stat
的连接尝试,它关闭了管道而不写入任何数据。
我会认为这是一个错误。 os.stat
不应该有这样的副作用。