python - 为什么 os.path.exists() 会阻止 Windows 命名管道连接?

标签 python windows named-pipes pywin32 python-3.7

似乎使用 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 会破坏窗口命名管道?

我已经排除了 python 多处理库。我在 os.path.exists 之后尝试了延迟。

这对我来说不是阻塞问题,但我很好奇。

最佳答案

os.path.exists 委托(delegate)给 os.stat,在 Windows 上,os.stat 尝试 open文件:

hFile = CreateFileW(path, access, 0, NULL, OPEN_EXISTING, flags, NULL);

然后它关闭文件。此时,除非服务器端先调用DisconnectNamedPipe,否则客户端无法重新打开管道。 ,这不会在此代码中发生。此外,当服务器端尝试从管道读取时,它正在从 os.stat 的连接尝试中读取,它关闭了管道而不写入任何数据。

我会认为这是一个错误。 os.stat 不应该有这样的副作用。

关于python - 为什么 os.path.exists() 会阻止 Windows 命名管道连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51255352/

相关文章:

python - 保存到 parquet 文件时如何使用新的 Int64 pandas 对象

python - 为什么我的具有函数范围的 pytest fixture 返回一个对象,该对象没有在新测试中重置它的类变量?

python - 转储时如何删除ns0标签

找不到配置文件/etc/startup.mk

windows - 用于打印出 sizeof 文件夹 cygwin 的 cmd 别名

windows - 如何从 Windows 上的命令行查看命名管道权限

c++ - 命名管道和 "GetNamedPipeHandleState"

python - 从两个排序数组中取前 10 个元素的最小总和组合

r - CRAN 发现警告 R CMD check --as-cran does not

c - 使用管道