Python进程通信之匿名管道实例讲解


Posted in Python onApril 11, 2015

匿名管道

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

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]"
Python 相关文章推荐
Python中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
Oct 23 Python
python基础学习之如何对元组各个元素进行命名详解
Jul 12 Python
python中的插值 scipy-interp的实现代码
Jul 23 Python
Django框架模板介绍
Jan 15 Python
Python函数参数匹配模型通用规则keyword-only参数详解
Jun 10 Python
Python 通过微信控制实现app定位发送到个人服务器再转发微信服务器接收位置信息
Aug 05 Python
Win下PyInstaller 安装和使用教程
Dec 25 Python
opencv resize图片为正方形尺寸的实现方法
Dec 26 Python
Django model.py表单设置默认值允许为空的操作
May 19 Python
Python流程控制语句的深入讲解
Jun 15 Python
Python使用socket模块实现简单tcp通信
Aug 18 Python
python lambda 表达式形式分析
Apr 03 Python
Python multiprocessing模块中的Pipe管道使用实例
Apr 11 #Python
Python httplib模块使用实例
Apr 11 #Python
初步探究Python程序的执行原理
Apr 11 #Python
Python与shell的3种交互方式介绍
Apr 11 #Python
Python函数参数类型*、**的区别
Apr 11 #Python
Python中的多重装饰器
Apr 11 #Python
Python中的各种装饰器详解
Apr 11 #Python
You might like
php cookies中删除的一般赋值方法
2011/05/07 PHP
php实现基于openssl的加密解密方法
2016/09/30 PHP
PHP用正则匹配form表单中所有元素的类型和属性值实例代码
2017/02/28 PHP
PHP实现ASCII码与字符串相互转换的方法
2017/04/29 PHP
PHP中Static(静态)关键字功能与用法实例分析
2019/04/05 PHP
由document.body和document.documentElement想到的
2009/04/13 Javascript
常用Extjs工具:Extjs.util.Format使用方法
2012/03/22 Javascript
poshytip 基于jquery的 插件 主要用于显示微博人的图像和鼠标提示等
2012/10/12 Javascript
js判断FCKeditor内容是否为空的两种形式
2013/05/14 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
JQuery select(下拉框)操作方法汇总
2015/04/15 Javascript
jQuery实现仿腾讯迷你首页选项卡效果代码
2015/09/17 Javascript
javascript性能优化之DOM交互操作实例分析
2015/12/12 Javascript
ES6新数据结构Set与WeakSet用法分析
2017/03/31 Javascript
详解webpack 多入口配置
2017/06/16 Javascript
利用JQuery操作iframe父页面、子页面的元素和方法汇总
2017/09/10 jQuery
Vue.js 实现微信公众号菜单编辑器功能(一)
2018/05/08 Javascript
对Vue2 自定义全局指令Vue.directive和指令的生命周期介绍
2018/08/30 Javascript
node.js事件轮询机制原理知识点
2019/12/22 Javascript
[55:44]完美世界DOTA2联赛决赛 FTD vs Phoenix 第二场 11.08
2020/11/11 DOTA
Python比较两个图片相似度的方法
2015/03/13 Python
Python实现识别手写数字 简易图片存储管理系统
2018/01/29 Python
python中的turtle库函数简单使用教程
2018/07/23 Python
Python程序打包工具py2exe和PyInstaller详解
2019/06/28 Python
Django框架视图介绍与使用详解
2019/07/18 Python
python Django编写接口并用Jmeter测试的方法
2019/07/31 Python
Python closure闭包解释及其注意点详解
2019/08/28 Python
基于python模拟TCP3次握手连接及发送数据
2020/11/06 Python
基于CSS3实现的黑色个性导航菜单效果
2015/09/14 HTML / CSS
工业自动化毕业生自荐信范文
2014/01/04 职场文书
高中运动会广播稿
2014/01/21 职场文书
预备党员入党自我评价范文
2014/03/10 职场文书
小学数学课后反思
2014/04/23 职场文书
2014年民政局关于保密工作整改措施
2014/09/19 职场文书
党员民主评议自我评价
2014/10/20 职场文书
2015中秋节晚会主持词
2015/07/01 职场文书