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 }

      

  • 相关阅读:
    chkconfig命令
    PHP中的WebService
    MySQL 中联合查询效率分析
    javascript中json对象长度
    Replace Pioneer
    c++ 调用matlab程序
    ubuntu 安装 sublime
    一些地址收藏
    学习笔记草稿
    Redis Cluster 集群使用(3)
  • 原文地址:https://www.cnblogs.com/zhiminyu/p/12524631.html
Copyright © 2011-2022 走看看