Python进程间通信之匿名管道

匿名管道

管道是一个单向通道,有点类似共享内存缓存.管道有两端,包括输入端和输出端.对于一个进程的而言,它只能看到管道一端,即要么是输入端要么是输出端.

os.pipe()返回2个文件描述符(r, w),表示可读的和可写的.示例代码如下:

#!/usr/bin/python
import time
import os

def child(wpipe):
    print(‘hello from child‘, os.getpid())
    while True:
        msg = ‘how are you\n‘.encode()
        os.write(wpipe, msg)
        time.sleep(1)

def parent():
    rpipe, wpipe = os.pipe()
    pid = os.fork()
    if pid == 0:
        child(wpipe)
        assert False, ‘fork child process error!‘
    else:
        os.close(wpipe)
        print(‘hello from parent‘, os.getpid(), pid)
        fobj = os.fdopen(rpipe, ‘r‘)
        while True:
            recv = os.read(rpipe, 32)
            print recv

parent()

输出如下:

(‘hello from parent‘, 5053, 5054)
(‘hello from child‘, 5054)
how are you

how are you

how are you

how are you

我们也可以改进代码,不用os.read()从管道中读取二进制字节,而是从文件对象中读取字符串.这时需要用到os.fdopen()把底层的文件描述符(管道)包装成文件对象,然后再用文件对象中的readline()方法读取.这里请注意文件对象的readline()方法总是读取有换行符’\n’的一行,而且连换行符也读取出来.还有一点要改进的地方是,把父进程和子进程的管道中不用的一端关闭掉.

#!/usr/bin/python
import time
import os

def child(wpipe):
    print(‘hello from child‘, os.getpid())
    while True:
        msg = ‘how are you\n‘.encode()
        os.write(wpipe, msg)
        time.sleep(1)

def parent():
    rpipe, wpipe = os.pipe()
    pid = os.fork()
    if pid == 0:
        os.close(rpipe)
        child(wpipe)
        assert False, ‘fork child process error!‘
    else:
        os.close(wpipe)
        print(‘hello from parent‘, os.getpid(), pid)
        fobj = os.fdopen(rpipe, ‘r‘)
        while True:
            recv = fobj.readline()[:-1]
            print recv

parent()

输出如下:

(‘hello from parent‘, 5108, 5109)
(‘hello from child‘, 5109)
how are you
how are you
how are you

如果要与子进程进行双向通信,只有一个pipe管道是不够的,需要2个pipe管道才行.以下示例在父进程新建了2个管道,然后再fork子进程.os.dup2()实现输出和输入的重定向.spawn功能类似于subprocess.Popen(),既能发送消息给子进程,由能从子子进程获取返回数据.

?

#!/usr/bin/python
#coding=utf-8
import os, sys

def spawn(prog, *args):
    stdinFd = sys.stdin.fileno()
    stdoutFd = sys.stdout.fileno()

    parentStdin, childStdout = os.pipe()
    childStdin, parentStdout= os.pipe()

    pid = os.fork()
    if pid:
        os.close(childStdin)
        os.close(childStdout)
        os.dup2(parentStdin, stdinFd)#输入流绑定到管道,将输入重定向到管道一端parentStdin
        os.dup2(parentStdout, stdoutFd)#输出流绑定到管道,发送到子进程childStdin
    else:
        os.close(parentStdin)
        os.close(parentStdout)
        os.dup2(childStdin, stdinFd)#输入流绑定到管道
        os.dup2(childStdout, stdoutFd)
        args = (prog, ) + args
        os.execvp(prog, args)
        assert False, ‘execvp failed!‘

if __name__ == ‘__main__‘:
    mypid = os.getpid()
    spawn(‘python‘, ‘pipetest.py‘, ‘spam‘)

    print ‘Hello 1 from parent‘, mypid #打印到输出流parentStdout, 经管道发送到子进程childStdin
    sys.stdout.flush()
    reply = raw_input()
    sys.stderr.write(‘Parent got: "%s"\n‘ % reply)#stderr没有绑定到管道上

    print ‘Hello 2 from parent‘, mypid
    sys.stdout.flush()
    reply = sys.stdin.readline()#另外一种方式获得子进程返回信息
    sys.stderr.write(‘Parent got: "%s"\n‘ % reply[:-1]) 

pipetest.py代码如下:

#coding=utf-8
import os, time, sys

mypid = os.getpid()
parentpid = os.getppid()
sys.stderr.write(‘child %d of %d got arg: "%s"\n‘ %(mypid, parentpid, sys.argv[1]))

for i in range(2):
    time.sleep(3)
    recv = raw_input()#从管道获取数据,来源于父经常stdout
    time.sleep(3)
    send = ‘Child %d got: [%s]‘ % (mypid, recv)
    print(send)#stdout绑定到管道上,发送到父进程stdin
    sys.stdout.flush()

输出:

child 7265 of 7264 got arg: "spam"
Parent got: "Child 7265 got: [Hello 1 from parent 7264]"
Parent got: "Child 7265 got: [Hello 2 from parent 7264]"
时间: 2024-11-03 14:39:27

Python进程间通信之匿名管道的相关文章

进程间通信IPC—匿名管道(pipe)和命名管道(fifo)

管道内部如何实现-大小,组织方式,环形队列? 一.进程间通信有多种方式,本文主要讲解对管道的理解.管道分为匿名管道和命名管道. (1)管道( pipe ):又称匿名管道.是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用.进程的亲缘关系通常是指父子进程关系. (2)命名管道 (named pipe或FIFO) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. 二.管道 1. 管道的特点: (1)管道是半双工的,数据只能向一个方向流动:双方通信时,需要

Linux进程间通信 -- 使用匿名管道

在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据. 一.什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|"来使用管道,但是管理的真正定义是什么呢?管道是一个进程连接数据流到另一个进程的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入. 举个例子,在shell中输入命令:ls -l

进程间通信之匿名管道

管道由pipe函数创建 #include<unistd.h> int pipe(int filedes[2]); 调用pipe函数在内核中开辟一块缓冲区(就是管道)用于通信,filedes[0]指向管道的读端,filedes[1]指向管道的写端.pipe函数调用成功返回0,调用失败返回-1. 比如,父进程关闭读端,子进程关闭写端.代码如下: 1   #include<stdio.h> 2   #include<string.h> 3   #include<unis

在Linux下的进程间通信之匿名管道

每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到.所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2 在从内核缓冲区把数据读走. 管道是一种最基本的IPC机制,由pipe函数创建: 调用pippe函数时在内核中开辟一块缓冲去(称为管道)用于通信,它有一个读端,一个写端,然后通过fileds参数传出给用户程序两个文件描述符,fileds[0]指向管道的读端,fileds[1]指向管道的写端,所以管道在用户程序看起来

进程间通信_02匿名管道

相关介绍                      分配一块独立于进程的内存,对内存的操作方式和对文件的操作方式类似.有如下特点: 1  只能用于父子进程之间. 2  管道的大小是有限制(一个页面的大小,4K字节). 3  数据是单向流动的. 4  传送的是无格式字节流,需要双方事先确定好长度 格式等. 操作函数 1 创建一个管道 #include <unistd.h> int pipe( int fildes[2] ); //出参,用于管道读写端的文件描述符: 返回值:0(成功)/-1(失败

Linux进程间通信 -- 使用命名管道

在前一篇文章—— Linux进程间通信 -- 使用匿名管道 中,我们看到了如何使用匿名管道来在进程之间传递数据,同时也看到了这个方式的一个缺陷,就是这些进程都由一个共同的祖先进程启动,这给我们在不相关的的进程之间交换数据带来了不方便.这里将会介绍进程的另一种通信方式——命名管道,来解决不相关进程间的通信问题. 一.什么是命名管道 命名管道也被称为FIFO文件,它是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但是它的行为却和之前所讲的没有名字的管道(匿名管道)类似. 由于Linux中所有

IPC——匿名管道

Linux进程间通信——使用匿名管道 在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它进程间可以交换更多有用的数据. 一.什么是管道 如果你使用过Linux的命令,那么对于管道这个名词你一定不会感觉到陌生,因为我们通常通过符号“|"来使用管道,但是管理的真正定义是什么呢?管道是一个进程连接数据流到另一个进程的通道,它通常是用作把一个进程的输出通过管道连接到另一个进程的输入. 举个例子

进程间通信(1)---匿名管道与命名管道

管道是进程间通信一种基本的的一种方式,管道又分为两种,匿名管道和命名管道,先说匿名管道 匿名管道(pipe) #include <unistd.h> int pipe(int filedes[2]); 调用pipe时会在内核中开辟一个缓冲区,使用时fileds[0]为输出端,fileds[1]为写入端口,调用成功时返回0,失败时返回-1: pipe的特点: 1:它只能在有血缘关系的进程间进行通信. 2:它只能进行单项通信,一个进程读,另一个只能写. 3:它是一种流式服务. 4:它的生命周期跟随

Linux - 进程间通信 - 匿名管道

一.概念:进程间通信( IPC,InterProcess Communication) 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进城之间要交换数据必须通过内核, 在内核中 开辟一块缓冲区进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内接提供的这种机制成为进程间 通信(IPC,InterProcess Communication). 二.管道 管道分为匿名管道和命名管道,这里我们只讲匿名管道,命名管道的实现将在下一篇文章中分享.