在断开连接之前等待命名管道被读取

Wait for Named Pipe to be read before Disconnecting

我有一个用 Python 编写的程序,我需要从 C++ 程序中联系它。我在 C++ 程序上创建管道服务器,客户端位于 Python。每次我尝试不同的行为时,我都不知道如何在这两个程序之间正确 read/write 。请注意,我希望管道在未来的多个 reads/writes 中保持打开状态。

服务器 (C++)

#include <windows.h>
#include <iostream>
using namespace std;

#define FGPIPE TEXT("\\.\pipe\FGChroma")

int main()
{

    HANDLE hPipe;
    DWORD dwWritten;
    DWORD MAX_BUF_SIZE = 8;

    hPipe = CreateNamedPipe(FGPIPE,
                            PIPE_ACCESS_OUTBOUND,
                            PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                            2,
                            MAX_BUF_SIZE*16,
                            0,
                            NMPWAIT_USE_DEFAULT_WAIT,
                            NULL
                            );

    cout<<"Pipe? "<<hPipe<<endl;

    cout<<"Awaiting Connection"<<endl;
    cout<<ConnectNamedPipe(hPipe, NULL)<<endl;
    cout<<"Connected"<<endl;
    WriteFile(hPipe, "MSG1\n", 5, &dwWritten, NULL);
    WriteFile(hPipe, "MSG2\n", 5, &dwWritten, NULL);
    FlushFileBuffers(hPipe);
    ///Need to Wait for read here
    cout<<"Disconnecting"<<endl;
    DisconnectNamedPipe(hPipe);

}

客户(Python)

f = open(r"\.\pipe\FGChroma", 'r', 0)
while True:
    value = f.read()
    print(value)

当我尝试在 Python 中执行 f.read() 时,我收到错误 OSError 22 Invalid Argument,这是公平的,因为我已经断开了管道。但是,如果我不断开管道,那么 Python 代码永远不会完成读取并一直等待,直到管道关闭或断开连接。我觉得解决方案很简单,我只是遗漏了一些让我头疼的小事。我阅读了命名管道和 Win API 的文档,我也尝试了 win32py 和其他替代方案,但我遇到了同样的问题;我不明白如何在 2 个实例之间保持连接并允许读取而无需断开连接或等待读取。

你可以在这里看看Python and Windows Named Pipes

认为 windows 由多个程序打开一个文件不像在 unix 上那样。如果你无法避免它使用 win32pipe 但这会使你的代码不是平台独立的

我认为 Python f.read() 和 Windows 管道有问题。也许我错过了一些东西,但是当你像你一样阅读管道时看起来没有 EOF,并且 python read() 会读到结尾和错误,即使它之前正确地读取了所有内容。

要解决此问题,您可以使用缓冲管道 (open(r"pipe", 'r')),然后一个一个地读取字符 (f.read(1)) 直到出现错误,或者使用 os.read(f.fileno(), 1024),这是较低的级别,在这种情况下有效。

根据上面 ElderBug 的回答,这里有一个不使用缓冲区但使用行尾终止符的可行解决方案。您可能需要相应地调整您的代码。

def read_line(file_handle):
    EOF = False
    data = ""
    while True:
        try:
            c = file_handle.read(1).decode("utf-8")
        except OSError: # EOF
            EOF = True
            break
        if c == '\n':
            break
        if not c:
            EOF = True
            break
        data += c
    return data, EOF

print("Connecting to Pipe")
while True:
    try:
        f = open(r"\.\pipe\FGChroma", 'rb', 0)
        break
    except FileNotFoundError:
        continue

print("Connected")

print("Reading Data")

while True:
    data, EOF = read_line(f)
    if EOF: break
    print(data)

您可能还需要将阅读模式从 'rb' 切换到 'r'。仅对二进制模式使用 b,但是您必须通过将缓冲模式从 0.

设置为 1 来启用缓冲