[英]How to open <del>named pipe</del>character device special file for reading and writing in Python
I have a service running on a Linux box that creates a 我有一个在Linux机器上运行的服务,可以创建一个 named pipe 命名管道 character device-special file, and I want to write a Python3 program that communicates with the service by writing text commands and reading text replies from the 字符设备特殊文件,我想编写一个Python3程序,通过编写文本命令和阅读文本回复来与服务进行通信 pipe 管 device. 设备。 I don't have source code for the service. 我没有该服务的源代码。
I can use os.open(named_pipe_pathname, os.O_RDWR)
, and I can use os.read(...)
and os.write(...)
to read and write it, but that's a pain because I have to write my own code to convert between bytes and strings, I have to write my own readline(...)
function, etc. 我可以使用os.open(named_pipe_pathname, os.O_RDWR)
,我可以使用os.read(...)
和os.write(...)
来读取和写入它,但这很痛苦,因为我必须写我自己的代码在字节和字符串之间转换,我必须编写自己的readline(...)
函数等。
I would much rather use a Python3 io
object to read and write the 我宁愿使用Python3 io
对象来读写 pipe 管 device, but every way I can think to create one returns the same error: 设备,但我能想到创建一个的方式返回相同的错误:
io.UnsupportedOperation: File or stream is not seekable.
For example, I get that message if I try open(pathname, "r+")
, and I get that same message if I try fd=os.open(...)
followed by os.fdopen(fd, "r+", ...)
. 例如,如果我尝试open(pathname, "r+")
,我会得到该消息,如果我尝试fd=os.open(...)
后跟os.fdopen(fd, "r+", ...)
我得到相同的消息fd=os.open(...)
os.fdopen(fd, "r+", ...)
Q: What is the preferred way for a Python3 program to write and read text to and from a 问:Python3程序在文本中写入和读取文本的首选方法是什么? named pipe 命名管道 character device? 角色设备?
Edit: 编辑:
Oops! 哎呀! I assumed that I was dealing with a named pipe because documentation for the service describes it as a "pipe" and, because it doesn't appear in the file system until the user-mode service runs. 我假设我正在处理一个命名管道,因为该服务的文档将其描述为“管道”,因为它在用户模式服务运行之前不会出现在文件系统中。 But, the Linux file
utility says it is in fact, a character device special file. 但是,Linux file
实用程序说它实际上是一个字符设备特殊文件。
You can use pexpect
. 你可以使用pexpect
。 Here is an example using two python modules: 以下是使用两个python模块的示例:
caller.py 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 backwards.py
x = ''
while True:
x = input(x[::-1] + ' > ')
caller.py
is using a "Pseudo-TTY device" to talk to backwards.py
. caller.py
正在使用“Pseudo-TTY设备”与backwards.py
交谈。 We are providing input with sendline
and capturing input with expect
(and the before
attribute). 我们使用expect
(以及before
属性)提供sendline
输入和捕获输入。
The problem occurs because attempting to use io.open
in read-write mode implicitly tries to wrap the underlying file in io.BufferedRandom
(which is then wrapped in io.TextIOWrapper
if in text mode), which assumes the underlying file is not only read/write, but random access, and it takes liberties (seeking implicitly) based on this. 出现该问题是因为试图使用io.open
在读写模式隐含地尝试包裹在底层文件io.BufferedRandom
(其然后包裹在io.TextIOWrapper
如果在文本模式下),其中假定基础文件是不是只读/ write,但随机访问,它基于此需要自由(寻求隐式)。 There is a separate class, io.BufferedRWPair
, intended for use with read/write pipes (the docstring specifically mentions it being used for sockets and two way pipes). 有一个单独的类io.BufferedRWPair
,用于读/写管道(docstring特别提到它用于套接字和双向管道)。
You can mimic the effects of io.open
by manually wrapping layer by layer to produce the same end result. 您可以通过逐层手动包装来模仿io.open
的效果,以产生相同的最终结果。 Specifically, for a text mode wrapper, you'd do something like: 具体来说,对于文本模式包装器,您可以执行以下操作:
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)
I believe this will close rawf
twice when txtf
is closed, but luckily, double-close is harmless here (the second close
does nothing, realizing it's already closed). 我相信当txtf
关闭时,这将关闭rawf
两次,但幸运的是,双关闭在这里是无害的(第二次close
什么也没做,意识到它已经关闭)。
It looks like you need to create separate handles for reading and for writing: to open read/write just requires a seek method. 看起来你需要为阅读和写入创建单独的句柄:打开读/写只需要一个搜索方法。 I couldn't figure out how to timeout reading, so it's nice to add an opener (see the docstring for io.open
) that opens the reader in non-blocking mode. 我无法弄清楚如何超时读取,所以最好添加一个开启器(参见io.open
的docstring),以非阻塞模式打开阅读器。 I set up a simple echo service on a named pipe called /tmp/test_pipe
: 我在名为/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()
''
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.