理解 Python 中的命名管道 (FIFO) [英] Understanding named Pipes (FIFO) in Python

查看:60
本文介绍了理解 Python 中的命名管道 (FIFO)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 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 at pipe_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆