zoukankan      html  css  js  c++  java
  • Linux_ pipe 匿名管道 浅解

    管道
    1 使用信号进行通信
    进程之间使用“信号”进行通信的优缺点
    优点:简单
    缺点:传递的信息有限,
    只能传递一个简单的“信号值”

    解决方案:
    使用“管道”进行进程间通信。

    注: 进程间通信,简称“IPC”
    2 什么是管道
    IPC 有多种方式, 管道是IPC的最基本的方式.
    管道是“半双工”的,即是单向的。
    管道是FIFO(先进先出)的。

    单进程中的管道:
    int fd[2]
    使用文件描述符fd[1], 向管道写数据
    使用文件描述符fd[0], 从管道读数据

    fd[0]
    用户进程
    fd[1]
    用户进程

    fd[1]
    fd[0]

    管道

    内核

    注:单进程中的管道无实际用处
    管道用于多进程间通信。

    3 管道的创建
    使用pipe系统调用
    用法:见 man 2 pipe

    返回值:
    成功:返回 0
    失败:返回 -1

    注意:获取两个“文件描述符”
    分别对应管道的读端和写端。
    fd[0]: 是管道的读端
    fd[1]: 是管道的写端
    如果对fd[0]进行写操作,对fd[1]进行读操作,可能导致不可预期的错误。

    4 管道的使用
    实例1:单进程使用管道进行通信
    main1. c
    注意:创建管道后,获得该管道的两个文件描述符,
    不需要普通文件操作中的open操作
    如图:

    实例2:多进程使用管道进行通信
    main2.c
    注意:创建管道之后,再创建子进程,此时一共有4个文件描述符。
    4个端口,父子进程分别有一个读端口和一个写端口
    向任意一个写端口写数据,即可从任意一个读端口获取数据。
    如图:

    实例3:子进程使用exec启动新程序时管道的使用
    main3.c

        有程序P1, P2
        使用管道进行通信
        P1由用户输入一个字符串,然后把该字符串发给p2
        P2接收到以后,把该字符串打印出来
    

    P1:
    创建管道
    创建子进程
    在子进程中用exec替换成p2,
    (在使用exec 时,把管道的读端作为exec的参数)
    在父进程中,获取用户的输入,然后把所输入的字符串发送给p2
    (即,父进程把字符串写入管道)

    P2:
    从参数中获取管道的读端(参数即为p2的main函数的参数)
    读管道
    把读到的字符串打印出来

    难点:子进程使用exec启动新程序运行后,
    新进程能够使用原来子进程的管道(因为exec能共享原来的文件描述符)
    但问题是新进程并不知道原来的文件描述符是多少!

    解决方案:
    把子进程中的管道文件描述符,用exec的参数传递给新进程。

    实例4:关闭管道的读端/写端

    管道关闭后的读操作:

    问题:
    对管道进行read时,如果管道中已经没有数据了,此时读操作将被“阻塞”。
    如果此时管道的写端已经被close了,则写操作将可能被一直阻塞!
    而此时的阻塞已经没有任何意义了。(因为管道的写端已经被关闭,即不会再写入数据了)

    解决方案:
    如果不准备再向管道写入数据,则把该管道的所有写端都关闭,
    则,此时再对该管道read时,就会返回0,而不再阻塞该读操作。(管道的特性)
    注意,这是管道的特性。
    如果有多个写端口,而只关闭了一个写端,那么无数据时读操作仍将被阻塞。

    实际实现方式:
    父子进程各有一个管道的读端和写端;
    把父进程的读端(或写端)关闭;
    把子进程的写端(或读端)关闭;
    使这个“4端口”管道变成单向的“2端口”管道,如图:

    代码:main4.c
    (改写main2.c)
    把父进程的写操作注释掉,此时子进程的读操作将被一直阻塞
    把父进程的写操作注释掉,并close父进程的写端
    此时子进程的读操作将将被阻塞。
    把父进程的写操作注释掉,并把父子进程的写端都close
    此时子进程读操作将直接返回0,而不再阻塞。
    最终实现方案:
    关闭父进程的读端,关闭子进程的写端。
    当父进程不再发送数据时,就关闭本进程的写端。

    练习:创建一个子进程
    父进程通过管道向子进程发送数据(字符串)
    该字符串由用户输入。
    当用户输入”exit”时, 就不再向子进程发送数据,并关闭该端的管道。

    子进程从管道读取数据,并输出。
    直到父进程关闭了管道的写端。
    

    练习:main5.c
    创建一个子进程
    父进程:
    循环等待用户输入,
    用户每输入一个单词后,就把该单词用管道发送给子进程,
    直到用户输入exit。
    子进程:
    每收到一个单词后,就打印输出
    直到用户在父进程中结束输入。

    实例5 把管道作为标准输入和标准输出
    把管道作为标准输入和标准输出的优点:
    子进程使用exec启动新程序时,就不需要再把管道的文件描述符传递给新程序了。
    可以直接使用使用标准输入(或标准输出)的程序。
    比如 od –c (统计字符个数,结果为八进制)

    实现原理:
    使用dup复制文件描述符
    用exec启动新程序后,原进程中已打开的文件描述符仍保持打开,
    即可以共享原进程中的文件描述符。

    代码:main6.c (修改main3.c)
    注意:dup的用法
    dup复制文件描述符,
    返回的新文件描述符和被复制的文件描述符,指向同一个文件或管道
    5 使用popen/pclose
    popen的作用:
    用来在两个程序之间传递数据:
    在程序A中使用popen调用程序B时,有两种用法:
    程序A读取程序B的输出(使用fread读取)
    程序A发送数据给程序B,以作为程序B的标准输入。(使用fwrite写入)

    用法:man popen
    返回值:成功,返回FILE*
    失败, 返回空
    实例1: 读取外部程序的输出
    main7.c
    实例2:把输出写到外部程序
    main8.c
    popen的原理:
    先使用fork创建一个子进程,
    然后在子进程中使用exec执行指定外部程序,并返回一个文件指针FILE*给父进程。
    当使用”r”时,该FILE指向外部程序的标准输出
    当使用”w”时,该FILE指向外部程序的标准输入。

    popen的优缺点:
    优点:可以使用shell扩展(比如命令中可以使用通配符)
    使用方便。
    缺点:每调用一次popen, 将要启动两个进程(shell和被指定的程序),
    资源消耗大。

    如果所有管道写端对应的文件描述符被关闭,则read返回0
    如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE

  • 相关阅读:
    最佳内存缓存框架Caffeine
    18个Java8日期处理的实践,太有用了
    windows 2003 IIS FTP 530 home directory inaccessible
    关闭应用程序(主程序)(WPF)
    解决Win8.1 IE11兼容性问题的方法
    Web页面性能测试工具浅析
    JS模板引擎handlebars.js的简单使用
    mvc4+entityFramework5 发布时遇到的纠结问题
    sqlserver 导入数据出现 无法创建 OLE DB 取值函数。请查看列元数据是否有效
    正则基础之——贪婪与非贪婪模式
  • 原文地址:https://www.cnblogs.com/Sico2Sico/p/5384217.html
Copyright © 2011-2022 走看看