我有一个用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和其他替代方法,但遇到了同样的问题;我不明白如何在两个实例之间保持连接状态并允许读取而不必断开连接或等待读取。
答案 0 :(得分:1)
我认为Python f.read()
和Windows管道存在问题。也许我错过了一些东西,但是当您像读取管道一样看起来没有EOF时,即使Python read()
之前读取的所有内容正确,它也会读取结尾并显示错误。
要解决此问题,可以使用缓冲管道(open(r"pipe", 'r')
),然后逐个读取字符(f.read(1)
)直到出现错误为止,或者使用os.read(f.fileno(), 1024)
,较低的级别,并且在这种情况下有效。
答案 1 :(得分:0)
您可以在这里Python and Windows Named Pipes
在Windows上通过多个程序打开文件的想法与在UNIX上不同。如果无法避免,请使用win32pipe,但这会使您的代码不是平台无关的
答案 2 :(得分:0)
根据上面的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
用于二进制模式,但是必须通过将缓冲模式从1
设置为0
来启用缓冲。