在断开连接之前等待读取命名管道
Posted
技术标签:
【中文标题】在断开连接之前等待读取命名管道【英文标题】:Wait for Named Pipe to be read before Disconnecting 【发布时间】:2020-08-31 13:18:09 【问题描述】:我有一个用 Python 编写的程序,我需要通过 C++ 程序联系它。我在 C++ 程序上创建管道服务器,客户端在 Python 中。每次我尝试不同的行为时,我都无法理解如何在两个程序之间正确读/写。请注意,我希望管道保持打开状态,以便将来进行多次读取/写入。
服务器 (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 个实例之间保持连接并允许读取而不必断开连接或等待读取。
【问题讨论】:
【参考方案1】:我认为 Python f.read()
和 Windows 管道存在问题。也许我错过了一些东西,但是当你像你一样读取管道时似乎没有 EOF,并且 python read()
将读取结束并出错,即使它之前正确读取了所有内容。
要解决此问题,您可以使用缓冲管道 (open(r"pipe", 'r')
),然后一个接一个地读取字符 (f.read(1)
) 直到出现错误,或者使用 os.read(f.fileno(), 1024)
,这是较低级别且有效在这种情况下。
【讨论】:
免责声明:我没有使用无缓冲管道进行测试,因为它在 python 3 中显然不受支持。 绝对了不起的答案。我怀疑这是 EOF 问题(因此为什么人们使用 win32py.ReadFile),但是您使用 f.read(1) 的解决方案效果很好!我将 1 替换为我的缓冲区大小,现在一切都稳定了。【参考方案2】:你可以看这里Python and Windows Named Pipes
在 windows 上通过多个程序打开一个文件并不像在 unix 上那样。如果您无法避免它,请使用 win32pipe 但这会使您的代码不独立于平台
【讨论】:
【参考方案3】:根据上面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
来启用缓冲。
【讨论】:
以上是关于在断开连接之前等待读取命名管道的主要内容,如果未能解决你的问题,请参考以下文章