zoukankan      html  css  js  c++  java
  • Linux_ mkfifo 命名管道 操作

    1. 管道的缺点
      管道只能在具有“亲戚”关系的进程之间通信。
      即仅当管道由某个进程创建之后,在该进程的所有子孙进程之间,可通过该管道来通信。

      其他情况下的无此“亲戚”关系的进程不能使用管道通信。

      解决办法:使用命名管道

    2. 什么是命名管道?
      命名管道是一种特殊的文件,
      命名管道以普通文件的形式(在文件系统中有一个确定的路径和文件名)存在。
      任意进程只要使用该文件就能通信。

      注意:无名管道(即管道),是通过文件描述符的形式使用。
      命名管道,是通过该命令管道文件的“文件名”来使用。

    3. 命名管道的创建
      1) 使用mkfifo
      用法: man 3 mkfifo
      原型: int mkfifo(const char *pathname, mode_t mode);
      参数: mode,类似于open的第三个参数,表示该管道的访问权限。
      pathname, 表示该命名管道的绝对路径。
      返回值:成功,返回0
      失败,返回-1
      实例: main1.c

                查看已创建的管道
                 (1) ls -l  /tmp/myfifo
                      第一个字符为p, 表示该文件是一个管道
                 (2) ls -F /tmp/myfifo
                      最后一个字符为|, 表示该文件是一个管道
      

      2) 使用mknod
      用法: man 2 mknod
      原型:int mknod(const char *pathname, mode_t mode, dev_t dev);
      参数:mode, 一定要含有 | S_IFIFO
      注:该API能用来创建各种特殊文件。
      dev, 取0
      实例:main2.c
      返回值:成功,返回0
      失败,返回-1

    4. 命令管道的使用
      1) 通过shell命令使用
      假设已有命名管道“/tmp/fifo”,

      (1) 从命名管道读数据,如果没有数据,则将被阻塞
      # cat  /tmp/myfifo            
      
      (2) 在另一个终端上,向该命名管道发送数据
      # echo hello  > /tmp/myfifo
      
      (3) 第(1)中的终端,将读取到数据。
      

      2) 通过open使用命名管道
      (1) open命名管道与open普通文件之间的区别:

            区别1:
           open命名管道时,不能以O_RDWR方式打开,只能以只读或只写方式打开。
                                    因为命名管道是单向的。
                                    如果以读写方式打开,结果将不可预期。
      
                                   如果要使用命名管道进行双向数据传输,只能:
                                    a) 创建两个命名管道,分别以不同方向打开。
                                    b) 只创建一个命名管道,
                                         先使用一个方向进行open,传递数据之后,再关闭。
                                         然后再用反方向方式打开,进行反方向传输。
      
         区别2:
         open命名管道时,O_NONBLOCK的意义与普通文件不同。
      
      
           区别3:
           open命名管道时,具有同步作用
      
      (2) open命名管道的合法方式:
           a) 只读阻塞式open
               open(MYFIFO,  O_RDONLY);
               效果:open操作将被阻塞,直到其他进程以写方式打开该FIFO
      
            b) 只写阻塞式open
                write(MYFIFO,  O_WRONLY);
                效果:open操作将被阻塞,直到其他进程以读方式打开该FIFO
      
            c) 只读非阻塞式open
                open(MYFIFO,  O_RDONLY | O_NONBLOCK);
                效果:马上成功返回,无论其他进程是否以写方式打开该FIFO
      
            d) 只写非阻塞式open
                open(MYFIFO,  O_WRONLY | O_NONBLOCK);
                效果:马上返回,无论其他进程是否以读方式打开该FIFO
                         如果其他进程没有以读方式打开该FIFO, 则返回-1,该FIFO打开失败。
                          如果其他进程已经以读方式打开该FIFO, 则返回一个文件描述符,打开成功。
      
           注意:对于FIFO, O_NONBLOCK对于只读和只写有不同的意义!
                    对于普通文件,O_NONBLOCK对于读和写的含义相同。
      
      1. 多进程使用FIFO时的常用组合方式
        多进程在打开FIFO时,能够获得“同步”。

        1) 进程A以只读阻塞式打开FIFO
        进程B以只写阻塞式打开FIFO
        最常用。

        2) 进程A以只读非阻塞式打开FIFO
        进程B以只写阻塞式打开FIFO

        3) 其他组合方式,不常用。

        实例:main3_r.c
        main3_w.c
        在不同终端上运行。

    5. 命名管道的读写
      1)读命名管道
      如果FIFO是以阻塞式打开的(即没有使用O_NONBLOCK)
      read时,如果当前该FIFO中没有数据,则阻塞read, 直到FIFO中被写入数据。
      如果当前该FIFO中有数据,则读取数据后返回。

       如果FIFO是以非阻塞式打开的(即使用O_NONBLOCK)
             read时,如果当前该FIFO中没有数据,则马上返回0。
                          如果当前该FIFO中有数据,则读取数据后返回。
      
       如果关闭了FIFO的写端文件描述符,则read直接返回0(无论是否是阻塞式read)
       该特性和两端口的管道相同。
      

      2) 写命名管道
      如果FIFO是以阻塞式打开的(即没有使用O_NONBLOCK)
      write时,如果当前该FIFO不能再写入数据时, 则阻塞write, 直到FIFO可被写入数据。
      如果当前该FIFO还能写入数据,则写数据后返回。

             注:该方式下,如果要写入的数据长度 <= PIPE_BUF, 则要么全部写入,要么都不写入。
      
      
       如果FIFO是以非阻塞式打开的(即使用O_NONBLOCK)
             write时候,如果该FIFO当前还能容纳要写入的全部数据,则写入全部数据后返回。
                             如果该FIFO当前已不能容纳要写入的全部数据,则
                                    如果要写入的数据长度 > PIPE_BUF ,    则写入部分数据,然后返回。
                                                                                           返回值为实际写入的字节数,也可能返回0
                                    如果要写入的数据长度 <= PIPE_BUF ,  则不写入任何数据,然后返回。
      
       如果关闭了FIFO的读端文件描述符,则write可能产生异常,而直接终止程序
      

      3) 写FIFO时的“原子性”
      如果写操作都是阻塞式的,而且每次要写入的数据长度 <= PIPE_BUF,
      那么,各进程的对该FIFO的写操作不会”交错”, 即都是原子性的。

      其他情况,可能发生“交错”。

      所以,每次要写入的字节数最好设置为PIPE_BUF。
      注意:PIPE_BUF在limits.h中定义

      1. 使用命名管道实现IPC
        注意:使用FIFO,进行进程间通信时存在“两级”同步:
        打开时,同步。
        读写时,同步。

        实例:main4.c
        进程A向进程B传送10M数据。
        并测试进程B读取10M数据所耗时间。

        练习:main5.c
        进程A循环等待用户输入,
        用户每输入一个单词后,就把该单词用管道发送给进程B,
        直到用户输入exit。

        进程B每收到一个单词后,就统计该单词的长度并打印输出
        直到进程A结束输入。

    6. 使用命令管道来创建服务器和客户端
      代码:
      版本1:客户端关闭时,服务器不关闭
      day5/server_client/
      版本2:客户端关闭时,服务器也关闭。
      day5/server.c
      day5/client.c

  • 相关阅读:
    03_已解决 [salt.master :2195][ERROR ][6219] Failed to allocate a jid. The requested returner 'mysql' could not be loaded.
    02_已解决 [salt.minion :1758][ERROR ][52886] Returner mysql.returner could not be loaded: 'mysql' __virtual__ returned False: Could not import mysql returner; mysql python client is not installed.
    05_centos7安装python3
    04_mysql安装
    03_mysql-python模块, linux环境下python2,python3的
    02_pip区别: linux环境下python2,python3的
    01 salt平台,软件架构图
    01_初识redis
    list_for_each_entry()函数分析
    趣解什么是网关
  • 原文地址:https://www.cnblogs.com/Sico2Sico/p/5384215.html
Copyright © 2011-2022 走看看