zoukankan      html  css  js  c++  java
  • shell 匿名管道和命名管道

    管道的特点:如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作;同理,写入管道的操作如果没有读取管道的操作,这一动作也会滞留。

    1,匿名管道

    匿名管道使用符号 |  表示,管道的两端时两个普通的,匿名的,打开的文件描述符:一端只读和一端只写。 

    cat file | less

    2,命名管道

    命名管道也称FIFO,先进先出,任何进程都可以通过FIFO共享数据;除非FIFO两端同时又读与写的进程,否则FIFO的数据量将会阻塞;

    匿名管道和命名管道的区别:

    • 匿名管道shell自动创建,存在于内核中;FIFO是又程序创建( mkfifo 命令),存在于系统文件中;
    • 匿名管道是单向的字节流,而FIFO则是双向的字节流。

    语法:

    mkfifo [ -m Mode ] Filename

    Mode用于设置权限

    退出状态:

    0  :成功创建所指定的FIFO特别文件

    >0:发生错误

    example2.1:

     [yuzhimin@gate02 shell_test]$ mkfifo -m 666 fifo_test2  

    结果如下:

    1 [yuzhimin@gate02 shell_test]$ ll fifo_test*
    2 prw-rw-rw-. 1 yuzhimin zmyu 0 Mar 19 15:14 fifo_test2

    example2.2:

    1 [yuzhimin@gate02 shell_test]$ mkfifo -m g-w,o-rw fifo_test4
    2 [yuzhimin@gate02 shell_test]$ mkfifo -m g+w fifo_test5
    3 [yuzhimin@gate02 shell_test]$ ll fifo_test*
    4 prw-r-----. 1 yuzhimin zmyu 0 Mar 19 15:17 fifo_test4
    5 prw-rw-rw-. 1 yuzhimin zmyu 0 Mar 19 15:18 fifo_test5

    参考资料:

    https://www.cnblogs.com/xianghang123/archive/2012/03/31/2427731.html

    示例

       1. 要使用许可权 prw-r–r– 创建 FIFO 特别文件,请输入:
          mkfifo  -m 644 /tmp/myfifo
          此命令使用所有者的读/写许可权以及组和其他用户的读许可权来创建 /tmp/myfifo 文件。
       2. 使用 -(减号)操作符创建一个 FIFO 特别文件以设置 prw-r—– 许可权,请输入:
          mkfifo  -m g-w,o-rw /tmp/fifo2
          此命令创建 /tmp/fifo2 文件,删除组的写权限和其他用户的所有许可权。

              注:如果多于一个的文件是用 -(减号)操作符创建的,那么用顿号分隔每个方式说明符,中间不用空格。

    文件

    /usr/bin/mkfifo     包含 mkfifo 命令。

    Linux下进程间通信:命名管道-mkfifo

    IPC Linux mkfifo mknode 命名管道 进程间通信

    摘要:进程间通信的方法有很多,FIFO与管道是最古老,也是相对来说更简单的一个通信机制。FIFO相对管道有一个优势,就是FIFO只要求两个进程是同一主机的,而不要求进程之间存在亲缘关系。FIFO是存在于文件系统的文件,可以使用诸如open、read、write等函数来操作。本文总结网络和APUE关于FIFO讨论,同时参考了Linux系统手册。

    目录 [隐藏]

    FIFO(命名管道)概述

    FIFO是一种进程通信机制,它突破通常管道无法进行无关进程之间的通信的限制,使得同一主机内的所有的进程都可以通信。FIFO是一个文件类型,stat结构中st_mode指明一个文件结点是不是一个FIFO,可以使用宏S_ISFIFO来测试这一点。

    当一个FIFO存在于文件系统里时,我们只需要在想进行通信的进程内打开这个文件就可以了。当然FIFO作为一个特殊的文件,它有一些不同普通文件特性,下面会详细详述它的读写规则,这些相对精通文件来有一定的区别。

    我们可以使用open、read、write来操作FIFO文件,从而实现进程间通信的目的。在shell环境下,也可以直接使用FIFO,这时往往与重写向有一些关联,一般系统都提供mkfifo实用程序来创建一个FIFO文件,这个程序实际上使用mkfifo系统调用来完成这个事。

    mkfifo函数

    mkfifo创建一个指定名字的FIFO,它的函数原型如下:

    #include<sys/stat.h>
    int mkfifo(const char* pathname, mode_t mode);
    返回值:成功,0;失败,-1

    参数pathname指出想要创建的FIFO路径,参数mode指定创建的FIFO访问模式。这个访问会与当前进程的umask进程运算,以产生实际应用的权限模式。

    mkfifo返回-1时表示创建过程中遇到某种错误,此时会设置errno,用户可以检测errno来取得进一步信息:

    EACCES: 路径所在的目录不允许执行权限EEXIST:路径已经存在,这时包括路径是一个符号链接,无论它是悬空还没有悬空。ENAMETOOLONG:要么全部的文件名大于PATH_MAX,要么是单独的文件名大于NAME_MAX。在GNU系统里没有这个文件名长度的限制,但在其它系统里可能存在。ENOENT:目录部分不存在,或者是一个悬空链接。ENOTDIR:目录部分不一个目录。EROFS:路径指向一个只读的文件系统。

    命名管道读写规则

    FIFO又叫命名管道,事实上它与管道确实在下许多相似之处,下面关于规则的讨论很体现这个相似。

    从FIFO中读取数据

    约定:如果一个进程为了从FIFO中读取数据而阻塞打开了FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。

    如果有进程写打开FIFO,且当前FIFO为空,则对于设置了阻塞标志的读操作来说,将一直阻塞下去,直到有数据可以读时才继续执行;对于没有设置阻塞标志的读操作来说,则返回0个字节,当前errno值为EAGAIN,提醒以后再试。对于设置了阻塞标志的读操作来说,造成阻塞的原因有两种:一、当前FIFO内有数据,但有其它进程在读这些数据;二、FIFO本身为空。
    解阻塞的原因是:FIFO中有新的数据写入,不论写入数据量的大小,也不论读操作请求多少数据量,只要有数据写入即可。读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程中有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时,读操作返回0)。如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数少于请求的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。从FIFO中写入数据

    约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。

    FIFO的长度是需要考虑的一个很重要因素。系统对任一时刻在一个FIFO中可以存在的数据长度是有限制的。它由#define PIPE_BUF定义,在头文件limits.h中。在Linux和许多其他类UNIX系统中,它的值通常是4096字节,Red Hat Fedora9下是4096,但在某些系统中它可能会小到512字节。

    虽然对于只有一个FIFO写进程和一个FIFO的读进程而言,这个限制并不重要,但只使用一个FIFO并允许多个不同进程向一个FIFO读进程发送请求的情况是很常见的。如果几个不同的程序尝试同时向FIFO写数据,能否保证来自不同程序的数据块不相互交错就非常关键了à也就是说,每个写操作必须“原子化”。

    设置了阻塞标志的写操作:

    当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。即写入的数据长度小于等于PIPE_BUF时,那么或者写入全部字节,或者一个字节都不写入,它属于一个一次性行为,具体要看FIFO中是否有足够的缓冲区。当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。

    没有设置阻塞标志的写操作:

    当要写入的数据量不大于PIPE_BUF时,Linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写。当要写入的数据量大于PIPE_BUF时,Linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。FIFO示例

    本段给出使用FIFO一个示例,它体现了两个使用FIFO的典型情景。

    创建FIFO

     1 #include<stdlib.h>
     2 #include<stdio.h>
     3 #include<sys/types.h>
     4 #include<sys/stat.h>
     5 int main()
     6 {
     7         int res = mkfifo("/tmp/my_fifo", 0777);
     8         if(res == 0)
     9         {
    10                 printf("FIFO created
    ");
    11         }
    12         exit(EXIT_SUCCESS);
    13 }

    使用FIFO

     1 #include<errno.h>
     2 #include<sys/stat.h>
     3 #include<fcntl.h>
     4 
     5 FIFO "/tmp/my_fifo"
     6 //本程序从一个FIFO读数据,并把读到的数据打印到标准输出
     7 //如果读到字符“Q”,则退出
     8 int main(int argc, char** argv)
     9 {
    10         char buf_r[100];
    11         int fd;
    12         int nread;
    13         if((mkfifo(FIFO, O_CREAT) < 0) && (errno != EEXIST))
    14         {
    15                 printf("不能创建FIFO
    ");
    16                 exit(1);
    17         }
    18 
    19         printf("准备读取数据
    ");
    20         fd = open(FIFO, O_RDONLY, 0);
    21         if(fd == -1)
    22         {
    23                 perror("打开FIFO");
    24                 exit(1);
    25         }
    26 
    27         while(1)
    28         {
    29                 if((nread = read(fd, buf_r, 100)) == -1)
    30                 {
    31                         if(errno == EAGAIN) printf("没有数据
    ");
    32                 }
    33 
    34                 //假设取到Q的时候退出
    35                 if(buf_r[0]=='Q') break;
    36 
    37                 buf_r[nread]=0;
    38                 printf("从FIFO读取的数据为:%s
    ", buf_r);
    39                 sleep(1);
    40         }
    41 
    42 }

      

  • 相关阅读:
    【SCOI 2011】 糖果
    【POJ 3159】 Candies
    【POJ 1716】 Integer Intervals
    【POJ 2983】 Is the information reliable?
    【POJ 1364】 King
    【POJ 1201】 Intervals
    【POJ 1804】 Brainman
    6月10日省中提高组题解
    【POJ 3352】 Road Construction
    【POJ 1144】 Network
  • 原文地址:https://www.cnblogs.com/zhiminyu/p/12524631.html
Copyright © 2011-2022 走看看