为什么 os.path.exists() 阻止 Windows 命名管道连接? [英] Why does os.path.exists() stop windows named pipes from connecting?

查看:89
本文介绍了为什么 os.path.exists() 阻止 Windows 命名管道连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎通过使用 os.path.exists() 成功测试了一个名为管道的窗口是否存在会阻止管道工作.为什么会这样?

It seems that a successful test of the existence of a windows named pipe by using os.path.exists() prevents the pipe from working. Why would this be?

这是成功运行的 Windows 命名管道代码:

Here is successfully working windows named-pipe code:

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()

这按预期工作,接收者打印收到的消息.

This works as expected, with the receiver printing the received message.

但是如果生产者中的三个注释掉的行没有被注释,os.path.exists(pipe_name) 调用会以某种方式破坏管道,因此输出变成:

But if the three commented-out lines in the producer are uncommented, the os.path.exists(pipe_name) call somehow breaks the pipe so the output becomes:

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 会破坏命名管道的窗口?

Why would os.path.exists break windows named pipes?

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

I've ruled out the python multiprocessing library. I've tried a delay after os.path.exists.

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

This is not a blocking problem for me, but I am curious.

推荐答案

os.path.exists 委托给 os.stat,在 Windows 上,os.stat 尝试打开 文件:

os.path.exists delegates to os.stat, and on Windows, os.stat tries to open the file:

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

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

Then it closes the file. At this point, the client can't reopen the pipe unless the server side first calls DisconnectNamedPipe, which doesn't happen in this code. Also, when the server side tries to read from the pipe, it's reading from os.stat's connection attempt, which closed the pipe without writing any data.

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

I would consider this a bug. os.stat should not have such side effects.

这篇关于为什么 os.path.exists() 阻止 Windows 命名管道连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆