我有一个在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程序在命名管道字符设备上写入和读取文本的首选方法是什么?
编辑:
糟糕!我假设我正在处理命名管道,因为该服务的文档将其描述为"管道"并且,因为在用户模式服务运行之前它不会出现在文件系统中。但是,Linux file
实用程序说它实际上是一个字符设备特殊文件。
答案 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()
''