理解 Python 中的命名管道 (FIFO) [英] Understanding named Pipes (FIFO) in Python
问题描述
我在 Unix 环境中运行 Python 2.7(在 Ubuntu 和 OSX 上测试)
我有以下程序:
<小时>使用 os.open():
[脚本 1]
导入操作系统pipe_1_name = "pipe_1"pipe_2_name = "pipe_2"pipe_3_name = "pipe_3"def set_connection():pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]对于 pipe_names 中的 pipe_name:如果 os.path.exists(pipe_name):os.remove(pipe_name)os.mkfifo(管道名称)别的:os.mkfifo(管道名称)pipe_1 = os.open(pipe_1_name, os.O_WRONLY)os.write(pipe_1, "server_message_0\n")pipe_2 = 打开(pipe_2_name,'r')收到 = pipe_2.readline()[:-1]打印[0]如果接收正确,现在处理:"+接收pipe_3 = 打开(pipe_3_name,'r')收到 = pipe_3.readline()[:-1]打印[1] 如果接收正确,现在处理:" + 接收打印已建立连接".返回管道_1、管道_2、管道_3定义主():管道 1、管道 2、管道 3 = set_connection()打印 str(pipe_1)打印 str(pipe_2)打印 str(pipe_3)如果 __name__ == "__main__":主要的()
[脚本 2]
导入操作系统pipe_1_name = "pipe_1"pipe_2_name = "pipe_2"pipe_3_name = "pipe_3"def get_connection():pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]对于 pipe_names 中的 pipe_name:如果不是 os.path.exists(pipe_name):raise Exception("Pipe "+pipe_name+" 不存在!")pipe_1 = 打开(pipe_1_name,'r')收到 = pipe_1.readline()[:-1]打印[0]如果接收正确,现在处理:"+接收pipe_2 = os.open(pipe_2_name, os.O_WRONLY)os.write(pipe_2, "client_message_0\n")pipe_3 = os.open(pipe_3_name, os.O_WRONLY)os.write(pipe_3, "client_message_1\n")打印已建立连接".返回管道_1、管道_2、管道_3定义主():管道 1、管道 2、管道 3 = get_connection()打印 str(pipe_1)打印 str(pipe_2)打印 str(pipe_3)如果 __name__ == "__main__":主要的()
逻辑很简单:
[管道 1]1. 脚本 1 打开一个到脚本 2 的写管道.2. 脚本 2 从管道中读取.[管道 2]3. 脚本 2 打开一个到脚本 1 的写管道.4. 脚本 1 从管道中读取.[管3]5. 脚本 2 打开一个到脚本 1 的写管道.6. 脚本 1 从管道中读取.
完全按预期工作.
<小时>问题来了.我不想使用 os.open().我想接收一个文件对象并用它来与管道接口.显然,这并非不可能,因为我可以从带有文件对象的管道中读取数据.但是,以下脚本不起作用.
<小时>没有 os.open()
[脚本 1]
导入操作系统pipe_1_name = "pipe_1"pipe_2_name = "pipe_2"pipe_3_name = "pipe_3"def set_connection():pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]对于 pipe_names 中的 pipe_name:如果 os.path.exists(pipe_name):os.remove(pipe_name)os.mkfifo(管道名称)别的:os.mkfifo(管道名称)pipe_1 = 打开(pipe_1_name,'w')pipe_1.write("server_message_0\n")pipe_2 = 打开(pipe_2_name,'r')收到 = pipe_2.readline()[:-1]打印[0]如果接收正确,现在处理:"+接收pipe_3 = 打开(pipe_3_name,'r')收到 = pipe_3.readline()[:-1]打印[1] 如果接收正确,现在处理:" + 接收打印已建立连接".返回管道_1、管道_2、管道_3定义主():管道 1、管道 2、管道 3 = set_connection()打印 str(pipe_1)打印 str(pipe_2)打印 str(pipe_3)如果 __name__ == "__main__":主要的()
[脚本 2]
导入操作系统pipe_1_name = "pipe_1"pipe_2_name = "pipe_2"pipe_3_name = "pipe_3"def get_connection():pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]对于 pipe_names 中的 pipe_name:如果不是 os.path.exists(pipe_name):raise Exception("Pipe "+pipe_name+" 不存在!")pipe_1 = 打开(pipe_1_name,'r')收到 = pipe_1.readline()[:-1]打印[0]如果接收正确,现在处理:"+接收pipe_2 = 打开(pipe_2_name,'w')pipe_2.write("client_message_0\n")pipe_3 = 打开(pipe_3_name,'w')pipe_3.write("client_message_1\n")打印已建立连接".返回管道_1、管道_2、管道_3定义主():管道 1、管道 2、管道 3 = get_connection()打印 str(pipe_1)打印 str(pipe_2)打印 str(pipe_3)如果 __name__ == "__main__":主要的()
它们看起来一样,不是吗?唯一的区别是我如何打开fifo.我使用 pipe = open(pipe_name, 'w')
而不是 os.open(pipe_name,os.O_WRONLY)
.
在第二组脚本中发生了什么,那些不使用 os.open() 的脚本,脚本 1 在 pipe_2 = open(pipe_2_name, 'r')
处阻塞,而脚本 2 阻塞在 pipe_2 = open(pipe_2_name, 'w')
.
为什么会这样?
对不起,文字墙.我对这个问题真的很困惑.
在第二组脚本中发生了什么,那些不使用os.open(),脚本 1 在
pipe_2 = open(pipe_2_name, 'r')
处阻塞,而脚本 2 在pipe_2 = open(pipe_2_name, 'w')
处阻塞.
否,received = pipe_1.readline()[:-1]
处的脚本 2 块.
为什么会这样?
这是因为脚本 1 的 open(pipe_1_name, 'w')
导致写入的消息以固定大小的块(通常为 4096 或 8192 字节)进行缓冲,因此 pipe_1.write("server_message_0\n")
尚未向管道写入任何内容,而仅向缓冲区写入任何内容,并且脚本 2 无法读取任何内容.参见 open() 和 python 多久刷新一次文件?
要解决这个问题,因为您的消息是完整的行,所以使用行缓冲就足够了,例如.g.
pipe_1 = open(pipe_1_name, 'w', 1)
(也适用于其他写入管道).
I am running Python 2.7 on a Unix environment (tested on Ubuntu and OSX)
I have the following programs:
With os.open():
[SCRIPT 1]
import os
pipe_1_name = "pipe_1"
pipe_2_name = "pipe_2"
pipe_3_name = "pipe_3"
def set_connection():
pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]
for pipe_name in pipe_names:
if os.path.exists(pipe_name):
os.remove(pipe_name)
os.mkfifo(pipe_name)
else:
os.mkfifo(pipe_name)
pipe_1 = os.open(pipe_1_name, os.O_WRONLY)
os.write(pipe_1, "server_message_0\n")
pipe_2 = open(pipe_2_name, 'r')
received = pipe_2.readline()[:-1]
print "[0] Now processing if received is correct: " + received
pipe_3 = open(pipe_3_name, 'r')
received = pipe_3.readline()[:-1]
print "[1] Now processing if received is correct: " + received
print "Connection established."
return pipe_1,pipe_2,pipe_3
def main():
pipe_1, pipe_2, pipe_3 = set_connection()
print str(pipe_1)
print str(pipe_2)
print str(pipe_3)
if __name__ == "__main__":
main()
[SCRIPT 2]
import os
pipe_1_name = "pipe_1"
pipe_2_name = "pipe_2"
pipe_3_name = "pipe_3"
def get_connection():
pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]
for pipe_name in pipe_names:
if not os.path.exists(pipe_name):
raise Exception("Pipe "+pipe_name+" does not exist!")
pipe_1 = open(pipe_1_name, 'r')
received = pipe_1.readline()[:-1]
print "[0] Now processing if received is correct: " + received
pipe_2 = os.open(pipe_2_name, os.O_WRONLY)
os.write(pipe_2, "client_message_0\n")
pipe_3 = os.open(pipe_3_name, os.O_WRONLY)
os.write(pipe_3, "client_message_1\n")
print "Connection established."
return pipe_1,pipe_2,pipe_3
def main():
pipe_1, pipe_2, pipe_3 = get_connection()
print str(pipe_1)
print str(pipe_2)
print str(pipe_3)
if __name__ == "__main__":
main()
The logic is simple:
[Pipe 1] 1. Script 1 opens a write pipe to Script 2. 2. Script 2 reads from the pipe. [Pipe 2] 3. Script 2 open a write pipe to Script 1. 4. Script 1 reads from the pipe. [Pipe 3] 5. Script 2 open a write pipe to Script 1. 6. Script 1 reads from the pipe.
Works exactly as expected.
Here is the problem. I don't want to use os.open(). I would like the receive a file object and use it to interface with the pipe. Clearly, it is not impossible since I can read from a pipe with a file object. However, The following script does not work.
Without os.open()
[Script 1]
import os
pipe_1_name = "pipe_1"
pipe_2_name = "pipe_2"
pipe_3_name = "pipe_3"
def set_connection():
pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]
for pipe_name in pipe_names:
if os.path.exists(pipe_name):
os.remove(pipe_name)
os.mkfifo(pipe_name)
else:
os.mkfifo(pipe_name)
pipe_1 = open(pipe_1_name, 'w')
pipe_1.write("server_message_0\n")
pipe_2 = open(pipe_2_name, 'r')
received = pipe_2.readline()[:-1]
print "[0] Now processing if received is correct: " + received
pipe_3 = open(pipe_3_name, 'r')
received = pipe_3.readline()[:-1]
print "[1] Now processing if received is correct: " + received
print "Connection established."
return pipe_1,pipe_2,pipe_3
def main():
pipe_1, pipe_2, pipe_3 = set_connection()
print str(pipe_1)
print str(pipe_2)
print str(pipe_3)
if __name__ == "__main__":
main()
[Script 2]
import os
pipe_1_name = "pipe_1"
pipe_2_name = "pipe_2"
pipe_3_name = "pipe_3"
def get_connection():
pipe_names = [pipe_1_name, pipe_2_name, pipe_3_name]
for pipe_name in pipe_names:
if not os.path.exists(pipe_name):
raise Exception("Pipe "+pipe_name+" does not exist!")
pipe_1 = open(pipe_1_name, 'r')
received = pipe_1.readline()[:-1]
print "[0] Now processing if received is correct: " + received
pipe_2 = open(pipe_2_name, 'w')
pipe_2.write("client_message_0\n")
pipe_3 = open(pipe_3_name, 'w')
pipe_3.write("client_message_1\n")
print "Connection established."
return pipe_1,pipe_2,pipe_3
def main():
pipe_1, pipe_2, pipe_3 = get_connection()
print str(pipe_1)
print str(pipe_2)
print str(pipe_3)
if __name__ == "__main__":
main()
They look the same, don't they? The only difference is how I open the fifo. Instead of os.open(pipe_name,os.O_WRONLY)
I use pipe = open(pipe_name, 'w')
.
What happens in the second set of scripts, the ones that don't use os.open(), Script 1 blocks at pipe_2 = open(pipe_2_name, 'r')
while Script 2 blocks at pipe_2 = open(pipe_2_name, 'w')
.
Why is this happening?
Sorry for the wall of text. I am really confused about this issue.
What happens in the second set of scripts, the ones that don't use os.open(), Script 1 blocks at
pipe_2 = open(pipe_2_name, 'r')
while Script 2 blocks atpipe_2 = open(pipe_2_name, 'w')
.
No, Script 2 blocks at received = pipe_1.readline()[:-1]
.
Why is this happening?
It's because Script 1's open(pipe_1_name, 'w')
causes the written message to be buffered in fixed-size chunks (typically 4096 or 8192 bytes), so the pipe_1.write("server_message_0\n")
does not yet write anything to the pipe, but only to the buffer, and Script 2 doesn't get anything to read. See open() and also How often does python flush to a file?
To cure this, since your messages are complete lines, it suffices to use line buffering, e. g.
pipe_1 = open(pipe_1_name, 'w', 1)
(as well for the other write pipes).
这篇关于理解 Python 中的命名管道 (FIFO)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!