Linux。 Python。从命名管道读取

Posted

技术标签:

【中文标题】Linux。 Python。从命名管道读取【英文标题】:Linux. Python. Read from named pipe 【发布时间】:2015-09-14 08:25:59 【问题描述】:

在 python 中复制某些功能时遇到问题。 在 ubuntu 下工作。 我有一个用 c++ 编写的程序,它会每隔一段时间将格式化的数据写入命名管道。我还有一个从该命名管道读取的 c++ 程序。那里没有问题。但是我几乎不知道如何在 python 中复制相同的东西(只有阅读部分)。

这是我用来阅读的 c++ 代码:

//various includes
#define FIFO_NAME "/tmp/MYFIFO"

using namespace std;

int main()

    int fp;
    fp = open(FIFO_NAME, O_RDONLY);
    char readbuf[80];
    while (true)
    
        int tot = 0;
        //read an int to know how many results are there to read right now
        while(tot<sizeof(int))
            tot+= read(fp, readbuf+tot, sizeof(int)-tot);
        int nres = *(int *)&readbuf[0];
        if (nres>0)
        
            cout << nres << " results:" << endl;
            for (int i = 0; i < nres; i++)
            
                //here I read 3 floats
            
        
    

这个 c++ 代码完全按照我的意愿工作:它从命名管道读取字节,将它们转换为相应的数字,让它们可供我使用。 我尝试在 python 中做同样的事情,但失败了。 第一次尝试python代码:

import os
import time

FIFO_NAME = '/tmp/MYFIFO'

def main():
    fp = os.open(FIFO_NAME, os.O_RDONLY)
    while True:
        time.sleep(0.001)
#Here I just try to read the first 4 bytes (the initial int) and fail already
        line = os.read(fp, 4) #I think this would read 4 bytes from the FIFO?
        print(len(line)) #ALWAYS prints 4
        print(line) #ALWAYS prints a blank line
        print(int(line)) #this of course gives an error, saying that line ==''

第二次尝试python代码(给出相同的错误结果):

import os
import time

FIFO_NAME = '/tmp/MYFIFO'

def main():
    fp = open(FIFO_NAME, 'r')
    while True:
        time.sleep(0.001)
#Here I try to read up to the line break
        line = fp.readline() #I think this would read to the line break, but it actually returns immediately
        print(len(line)) #after the first few iterations, this always prints 6
        print(line) #ALWAYS prints a blank line

在第二次尝试中,我希望阅读到第一个换行符(我可以很容易地让 c++ 生产者在每个“数据包”的末尾放置一个换行符)。然而,这总是读取空行。

我的问题是关于在 python 中获得我在 c++ 中的功能。我可以通过两种方式看到这种情况:

通过像在 c++ 中那样实际读取字节并将其编组为正确的数据类型和值来修复我在 python 端使用管道的方式。 让python“加载”一个字节缓冲区,直到它收到换行符,然后从那里提取我的数字。

无论哪种方式,我都不明白为什么 read 和 readline 返回那些空白字符串,也不知道如何处理它们。

我希望你们中的一些人可以帮助我。随时要求澄清和更多信息。

【问题讨论】:

*(int *)&amp;readbuf[0] - 这不是可移植的,您依赖于正确的 int 大小和字节序。 @KarolyHorvath 我知道,但是这段代码(还)不需要是可移植的。 我以为你用sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)从管道中读取,显然不是! @RolfofSaxony 老实说,我不知道。绝对不是在 C++ 中。 你必须解压数据:docs.python.org/2/library/struct.html 【参考方案1】:

在我的评论中,我指的是 python,但那是 by。 看看这个,它可能会对你有所帮助,因为它专门关于“C# 和 Python 之间的命名管道”。http://jonathonreinhart.blogspot.co.uk/2012/12/named-pipes-between-c-and-python.html

如果链接丢失,乔纳森是这样说的:

C#

// Open the named pipe.
var server = new NamedPipeServerStream("NPtest");

Console.WriteLine("Waiting for connection...");
server.WaitForConnection();

Console.WriteLine("Connected.");
var br = new BinaryReader(server);
var bw = new BinaryWriter(server);

while (true) 
    try 
        var len = (int) br.ReadUInt32();            // Read string length
        var str = new string(br.ReadChars(len));    // Read string

        Console.WriteLine("Read: \"0\"", str);

        str = new string(str.Reverse().ToArray());  // Just for fun

        var buf = Encoding.ASCII.GetBytes(str);     // Get ASCII byte array     
        bw.Write((uint) buf.Length);                // Write string length
        bw.Write(buf);                              // Write string
        Console.WriteLine("Wrote: \"0\"", str);
    
    catch (EndOfStreamException) 
        break;                    // When client disconnects
    


Console.WriteLine("Client disconnected.");
server.Close();
server.Dispose();

Python

import time
import struct

f = open(r'\\.\pipe\NPtest', 'r+b', 0)
i = 1

while True:
    s = 'Message[0]'.format(i)
    i += 1

    f.write(struct.pack('I', len(s)) + s)   # Write str length and str
    f.seek(0)                               # EDIT: This is also necessary
    print 'Wrote:', s

    n = struct.unpack('I', f.read(4))[0]    # Read str length
    s = f.read(n)                           # Read str
    f.seek(0)                               # Important!!!
    print 'Read:', s

    time.sleep(2)

在这个例子中,我实现了一个非常简单的协议,其中每个“消息”都是一个 4 字节的整数(C# 中的 UInt32,Python 中的 'I' (un)pack 格式),它表示字符串的长度跟随。字符串是 ASCII。此处需要注意的重要事项:

Python open() 的第三个参数表示“无缓冲”。 否则,它将默认为行缓冲,这意味着它将在实际通过管道发送之前等待换行符。

我不知道为什么,但是省略 seek(0) 会导致 IOError #0。 *** 问题向我提示了这一点。

【讨论】:

这个搜索是必要的,因为你在写作和阅读之间切换。这有点令人困惑,因为管道传统上是不可搜索的,并且您通常会单独打开端点。 太好了。从你的回答中我得到了正确的答案。由于在 python 方面我只是在阅读,所以 f.seek(0) 实际上给出了一个错误。感谢您找到该参考资料。

以上是关于Linux。 Python。从命名管道读取的主要内容,如果未能解决你的问题,请参考以下文章

从命名管道、C 程序(编写器)和 Python(读取器)获取额外数据

Python 可以从 Windows Powershell 命名管道中读取吗?

Python 从命名管道/FIFO 中读取 JSON

使用 cmd.exe 或 PowerShell 或 Python 从 Windows 命名管道中读取

OpenCV Python,从命名管道中读取视频

检测命名管道的关闭