如何在Python中打开<del>命名管道</del>字符设备专用文件进行读写

时间:2018-01-24 20:54:16

标签: python linux python-3.x

我有一个在Linux机器上运行的服务,它创建一个命名管道字符设备特殊文件,我想编写一个Python3程序,通过编写文本命令和阅读文本与服务进行通信来自 pipe 设备的回复。我没有该服务的源代码。

我可以使用os.open(named_pipe_pathname, os.O_RDWR),我可以使用os.read(...)os.write(...)来读取和写入它,但这很痛苦,因为我必须编写自己的代码进行转换在字节和字符串之间,我必须编写自己的readline(...)函数等。

我更愿意使用Python3 io对象来读取和写入 pipe 设备,但我能想到的每一种方法都会返回相同的错误:

io.UnsupportedOperation: File or stream is not seekable.

例如,如果我尝试open(pathname, "r+"),我会收到该消息,如果我尝试fd=os.open(...)后跟os.fdopen(fd, "r+", ...),我会收到同样的消息。

问:Python3程序在命名管道字符设备上写入和读取文本的首选方法是什么?

编辑:

糟糕!我假设我正在处理命名管道,因为该服务的文档将其描述为&#34;管道&#34;并且,因为在用户模式服务运行之前它不会出现在文件系统中。但是,Linux file实用程序说它实际上是一个字符设备特殊文件。

3 个答案:

答案 0 :(得分:1)

解决方案

您可以使用pexpect。以下是使用两个python模块的示例:

<强> caller.py

import pexpect

proc = pexpect.spawn('python3 backwards.py')
proc.expect(' > ')

while True:

    n = proc.sendline(input('Feed me - '))
    proc.expect(' > ')
    print(proc.before[n+1:].decode())

<强> backwards.py

x = ''

while True:
    x = input(x[::-1] + ' > ')

解释

caller.py正在使用&#34; Pseudo-TTY设备&#34;与backwards.py交谈。我们使用sendline提供输入,并使用expect(以及before属性)捕获输入。

答案 1 :(得分:1)

出现此问题是因为尝试在读写模式下使用io.open会隐式尝试将基础文件包装在io.BufferedRandom中(如果处于文本模式,则会将其包装在io.TextIOWrapper中),假设底层文件不仅是读/写,而是随机访问,它基于此需要自由(寻求隐式)。有一个单独的类io.BufferedRWPair,用于读/写管道(docstring特别提到它用于套接字和双向管道)。

您可以通过逐层手动包装来模仿io.open的效果,以产生相同的最终结果。具体来说,对于文本模式包装器,您可以执行以下操作:

rawf = io.FileIO(named_pipe_pathname, mode="rb+")
with io.TextIOWrapper(io.BufferedRWPair(rawf, rawf), encoding='utf-8', write_through=True) as txtf:
    del rawf   # Remove separate reference to rawf; txtf manages lifetime now
    # Example use that works (but is terrible form, since communicating with
    # oneself without threading, select module, etc., is highly likely to deadlock)
    # It works for this super-simple case; presumably you have some parallel real code
    txtf.write("abcé\n")
    txtf.flush()
    print(txtf.readline(), flush=True)

我相信当rawf关闭时会关闭txtf两次,但幸运的是,双关闭在这里是无害的(第二个close什么都不做,意识到它已经闭)。

答案 2 :(得分:0)

看起来您需要为读取和写入创建单独的句柄:打开读/写只需要一个搜索方法。我无法弄清楚如何超时读取,所以最好添加一个开启器(参见io.open的文档字符串),以非阻塞模式打开阅读器。我在名为/tmp/test_pipe的命名管道上设置了一个简单的echo服务:

In [1]: import io
In [2]: import os
In [3]: nonblockingOpener = lambda name, flags:os.open(name, flags|os.O_NONBLOCK)
In [4]: reader = io.open('/tmp/test_pipe', 'r', opener = nonblockingOpener)
In [5]: writer = io.open('/tmp/test_pipe', 'w')
In [6]: writer.write('Hi have a line\n')
In [7]: writer.flush()
In [8]: reader.readline()
Out[8]: 'You said: Hi have a line\n'
In [9]: reader.readline()
''