精华内容
下载资源
问答
  • mkfifo

    千次阅读 2016-10-07 09:39:00
    管道是Linux的十种文件类型之一,使用管道通信本质上还是以文件作为通信的媒介 有名管道+无名管道=管道 有名管道(FIFO文件):就是 有文件名的...mkfifo $mkfifo a.pipe $ls -l prw-rw-r-- 1 jiang jiang 0 10月 7 ...

    管道是Linux的十种文件类型之一,使用管道通信本质上还是以文件作为通信的媒介

    有名管道+无名管道=管道

    有名管道(FIFO文件):就是 有文件名的管道, 可以用于任意两个进程间的通信

    无名管道(pipe文件):就是没有文件名的管道, 只能用于父子进程之间的通信

    mkfifo

    $mkfifo a.pipe
    $ls -l
    prw-rw-r--  1 jiang jiang     0 10月  7 08:47 pipe|

    创建有名管道,管道不能执行,不可写入, 就像吸管,一边堵死, 另外一头也传不进,就在管口堵着, 还是一个非常短,短到不能存储一丁点饮料的吸管只有读端打开的时候写端的数据才能通过管道抵达目的地, 管道本身可不会存放任何数据

    在terminal_1:

    $echo hello > pipe  #打开管道的写端
                        #卡在那, 因为读端没有打开, 就像咬紧吸管不抽气, 饮料就进不到吸管

    在terminal_2:

    $cat   pipe         #打开管道的读端
    hello               #读端打开了, 管道就通了, 实现了在两个terminal(两个进程)之间的通信 

    回到terminal_1

    $echo hello > pipe  #打开管道的写端
    $                   #数据被传出了, terminal_1就结束卡顿了
    展开全文
  • 使用mkfifo命令可以使用指定的名称创建先进先出文件(FIFO) 语法格式:mkfifo [参数] [名称] 常用参数: -m 设置权限模式,类似chmod -Z 将每个创建的目录SELinux安全环境设置为CTX 参考实例 创建FIFO...
  • mkfifo.rar

    2019-07-31 20:37:35
    首先利用mkfifo函数创建管道,注意需要使用有效路径;然后按照路径打开管道,由于本程序使用读取文件,所以文件权限使用O_RDONLY为只读权限,然后设立一个死循环不断读取管道文件的数据,当接收到另一个进程B写入到...
  • int mkfifo(const char *pathname, mode_t mode);int mknod(const char *pathname, mode_t mode, dev_t dev);管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信。在有名管道(named pipe或FIFO)...

    int mkfifo(const char *pathname, mode_t mode);

    int mknod(const char *pathname, mode_t mode, dev_t dev);

    管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信。

    在有名管道(named pipe或FIFO)提出来之后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径与之关联,

    以FIFO的文件形式存储于文件系统中。有名管道是一个设备文件。因此,即使进程与创建FIFO的进程不存在亲缘关系,

    只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是,FIFO(first in first out)总是按照先进先出的原则工作,

    第一个被写入的数据将首先从管道中读出。

    有名管道的创建与读写

    LINUX下有两种方式创建有名管道。一是在Shell下交互地建立一个有名管道,二是在程序中使用系统函数建立有名管道。

    shell方式下可使用mknod或mkfifo命令,下面命令使用mknod创建一个有名管道:

    mknod namedpipe

    ----------------------------------------------------------------

    创建有名管道的函数有两个:mknod和mkfifo

    int mkfifo(const char *pathname, mode_t mode);

    int mknod(const char *pathname, mode_t mode, dev_t dev);

    函数mknod参数中path为创建的有名管道的全路径名;mod为创建的有名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,

    它只在创建设备文件时才会用到。

    umask(0);

    if (mknod("/tmp/fifo", S_IFIFO|0666, 0) == -1)

    {

    perror("mknod error!");

    exit(1);

    }

    umask(0);

    if (mkfifo("/tmp/fifo", S_IFIFO|0666) == -1)

    {

    perror("mkfifo error!");

    exit(1);

    }

    S_IFIFO|0666 指明创建一个有名管道且存取权限为0666,即创建者、与创建者同组的用户、其他用户对该有名管道的  访问权限 都是 可读可写。

    有名管道创建后就可以使用了,有名管道和管道的使用方法基本是相同的。只是使用有名管道时,必须先调用open将其打开。因为有名管道

    是一个存在于硬盘上的文件,而管道是存在于内存中的特殊文件。

    需要注意的是,调用open打开有名管道的进程可能会被阻塞。但如果同时用读写方式(O_RDWR)打开,则一定不会导致阻塞;如果以只读方式

    (O_RDONLY)打开,则调用open函数的进程将会被阻塞直到有写方式打开管道;同样以写方式(O_WRONLY)打开也会阻塞直到有读方式打开管道。

    实例:

    写端:

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #define FIFO_NAME "testfifo"

    int main(int argc, char* argv[])

    {

    int fd;

    char buf[] = "yyyyyyy";

    mkfifo(FIFO_NAME, S_IFIFO|);

    fd = open(FIFO_NAME, O_WRONLY);

    write(fd, buf, strlen(buf)+);

    close(fd);

    unlink(FIFO_NAME);//删除管道文件

    sleep(1);

    return ;

    }

    读端:

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #define FIFO_NAME "testfifo"

    #define BUF_SIZE 1024

    int main(int argc, char* argv[])

    {

    int fd;

    char buf[BUF_SIZE];

    fd = open(FIFO_NAME, O_RDONLY);

    read(fd, buf, BUF_SIZE);

    printf("%s\n", buf);

    close(fd);

    return ;

    }

    Linux 进程通信(有名管道)

    有名管道(FIFO) 有名管道是持久稳定的. 它们存在于文件系统中. FIFO比无名管道作用更大,因为他们能让无关联的进程之间交换数据. 管道文件一般用于交换数据. shell命令创建管道 一个she ...

    Unix/Linux进程间通信(二):匿名管道、有名管道 pipe()、mkfifo()

    1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...

    linux进程间通信-有名管道(FIFO)

    有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的 ...

    Linux进程间通信IPC学习笔记之有名管道

    基础知识: 有名管道,FIFO先进先出,它是一个单向(半双工)的数据流,不同于管道的是:是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)有一个与路径名关联的名 ...

    linux进程间通信--有名管道

    有名管道 只有当一个库函数失败时,errno才会被设置.当函数成功运行时,errno的值不会被修改.这意味着我们不能通过测试errno的值来判断是否有错误存在.反之,只有当被调用的函数提示有错误发生时 ...

    Linux系统编程(11)——进程间通信之有名管道

    管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服.FIFO不同于管道之处在于它提供一个路径名与之关联,以 ...

    linux 有名管道(FIFO)

    http://blog.csdn.net/firefoxbug/article/details/8137762 linux 有名管道(FIFO) 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时 ...

    linux之有名管道

    有名管道1.查看命令:man 3 mkfifo 2.头文件:#include #include 3.函数原型:int mk ...

    Linux网络编程学习(七) ----- 有名管道(第四章)

    1.什么是有名管道?为什么有了管道还需要有名管道? 有名管道是解决管道不能提供非父子进程间通信的缺陷.管道在Linux系统内部是以文件节点(inode)的形式存在,但由于其对外的不可见性(“无名”性) ...

    随机推荐

    机器人聊天的小Demo

    先来张图,看看我们要做成什么样的效果.很简单的一个发送消息接收消息的界面,那怎么实现的呢,毫无疑问,是ListView的多布局了,右边显示我们发送消息的条目,左边显示要接收消息的条目.下面是一个Edi ...

    red5研究(一):下载,工程建立、oflaDemo安装、demo测试

    一.red5下载.添加工程到myeclipse 1,从官网上下载red51.01版本(我下载的是red51.0的版本),下载链接http://www.red5.org/downloads/red5/1 ...

    SGU 113.Nearly prime numbers

    水一个代码: #include using namespace std; int n, a; bool ok; bool prime (int x) { ; i * ...

    调不尽的内存泄漏,用不完的Valgrind

    调不尽的内存泄漏,用不完的Valgrind Valgrind 安装 1. 到www.valgrind.org下载最新版valgrind-X.X.X.tar.bz2 2. 解压安装包:tar –jxvf ...

    win10怎么安装JDK8,配置JDK8的环境变量

    win10怎么安装JDK8,配置JDK8的环境变量 本文详细说明怎么在win10上安装JDK8,方便小伙伴们快速学会安装与配置JDK. 工具/原料 windows10 jdk-8u51-windows ...

    TensorFlow实现回归

    数据:fetch_california_housing(加利福尼亚的房价数据) 1.解析解法 import tensorflow as tf import numpy as np from sklea ...

    python实现以application/json格式为请求体的http post请求

    接口传递数据格式类型为json格式,如下图抓包查看 Python实现脚本请求接口并以中文打印接口返回的数据 import json import requests url = "https: ...

    nginx for Windows Known issues:path

    http://nginx.org/en/docs/windows.html nginx/Windows uses the directory where it has been run as the ...

    展开全文
  • mkfifo_w/mkfifo_r.cpp

    2020-12-05 20:16:15
    mkfifo_w.cpp /* * function: 演示使用mkfifo创建管道,并实现无血缘关系的进程间通信 * 此进程为写端 * * 2020-12-05 */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #...

    mkfifo_w.cpp

    /*
     * function: 演示使用mkfifo创建管道,并实现无血缘关系的进程间通信
     *           此进程为写端
     *
     * 2020-12-05
     */
    
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(int argc, char *argv[])
    {
        int ret = mkfifo("mytestfifo", 0644);   // 创建管道
        if (ret < 0)
        {   
            perror("mkfifo faild");
            exit(1);
        }   
        printf("创建管道完成\n");
    
        int fd = open("mytestfifo", O_WRONLY);      // 以只写权限打开管道
        if (fd < 0)
        {   
            perror("open faild");
            exit(1);
        }   
    
        char buf[] = "hello world";
    
        write(fd, buf, sizeof(buf));    // 向管道写入buf
    
        printf("写管道完成\n");
    
        return 0;
    }
    

    mkfifo_r.cpp

    /*
     * function: 演示使用mkfifo创建管道,并实现无血缘关系的进程间通信
     *           此进程为读端
     *
     * 2020-12-05
     */
    
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(int argc, char *argv[])
    {
        // 在写端已经创建管道
    
        sleep(2);
    
        int fd = open("mytestfifo", O_RDONLY);      // 以只读权限打开管道
        if (fd < 0)
        {   
            perror("open faild");
            exit(1);
        }   
    
        char buf[256] = {0};
    
        int n = read(fd, buf, sizeof(buf));
        if (n < 0)
        {   
            perror("read faild");
            exit(1);
        }   
    
        printf("%s\n", buf);
    
        return 0;
    }
    

    在这里插入图片描述

    展开全文
  • mkfifo函数

    千次阅读 2015-04-27 18:10:49
    mkfifo函数   mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说,匿名管道是不可见的,...

    mkfifo函数 


        mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名管道。前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说,匿名管道是不可见的,它的作用仅限于在父进程和子进程两个进程间进行通信。而命名管道是一个可见的文件,因此,它可以用于任何两个进程之间的通信,不管这两个进程是不是父子进程,也不管这两个进程之间有没有关系。Mkfifo函数的原型如下所示:
     #include <sys/types.h>
        #include <sys/stat.h>
    int mkfifo( const char *pathname, mode_t mode );


         mkfifo函数需要两个参数,第一个参数(pathname)是将要在文件系统中创建的一个专用文件。第二个参数(mode)用来规定FIFO的读写权限。Mkfifo函数如果调用成功的话,返回值为0;如果调用失败返回值为-1。下面我们以一个实例来说明如何使用mkfifo函数建一个fifo,具体代码如下所示:


        int ret;
        ...
        ret = mkfifo( "/tmp/cmd_pipe", S_IFIFO | 0666 );
        if (ret == 0) ...{
          // 成功建立命名管道
        } else ...{
          // 创建命名管道失败
    }


        在这个例子中,利用/tmp目录中的cmd_pipe文件建立了一个命名管道(即fifo)。之后,就可以打开这个文件进行读写操作,并以此进行通信了。命名管道一旦打开,就可以利用典型的输入输出函数从中读取内容。举例来说,下面的代码段向我们展示了如何通过fgets函数来从管道中读取内容:


     pfp = fopen( "/tmp/cmd_pipe", "r" );
        ...
    ret = fgets( buffer, MAX_LINE, pfp );


        我们还能向管道中写入内容,下面的代码段向我们展示了利用fprintf函数向管道写入的具体方法:


      pfp = fopen( "/tmp/cmd_pipe", "w+ );
        ...
    ret = fprintf( pfp, "Here’s a test string!\n" );




        对命名管道来说,除非写入方主动打开管道的读取端,否则读取方是无法打开命名管道的。Open调用执行后,读取方将被锁住,直到写入方出现为止。尽管命名管道有这样的局限性,但它仍不失为一种有效的进程间通信工具。


        上面介绍的是与管道有关的一些系统调用,下面介绍管道命令相关的系统命令。 




    与管道相关的系统命令 


        现在开始,我们来研究与进程间通信密切相关的一些系统命令。首先介绍的是mkfifo命令,它的功能与mkfifo系统调用相似,只不过它是用来在命令行中建立一个命名管道。


        在命令行下建立fifo的专用文件,即命名管道的常用方法有两个,mkfifo命令便是其中之一。mkfifo命令的一般用法如下所示:
    mkfifo [options] name


        这里的options一般为-m,即模式,用以指出读写权限;name是要创建的管道的名称,必要时可以加上路径。如果我们没有规定权限,该命令会采取默认值0644。这里以一个具体实例来说明如何在/tmp目录下面建立一个称为cmd_pipe的命名管道:
    $ mkfifo /tmp/cmd_pipe


        下面用例子说明如何给命名管道指定读写权限。这里我们先将前面建立的管道删掉,然后重新建立管道,并指定管道的权限为0644,当然您也可以指定其他权限:


        $ rm cmd_pipe
    $ mkfifo -m 0644 /tmp/cmd_pipe


        上面的权限一经建立,就能够在命令行行下通过此管道进行通信了。比如,可以在一个终端上,利用cat命令来读取管道:


    $ cat cmd_pipe


        当输入该命令后,我们的进程就会被挂起,等待写入程序打开此管道。现在,在另一个终端上利用echo命令向这个命名管道写入:
        $ echo Hi > cmd_pipe


        这个命令结束后,要读取该管道的程序(即cat)将被唤醒,然后结束。为醒目起见,这里列出完整的读取方(也就是读取管道的程序)输入的命令和得到的结果:


    $ cat cmd_pipe
    Hi
    $


        由此看来,命名管道不仅在C程序中非常有用,而且在脚本中作用也很大。当然,如果组合使用,效果也是很好的。


        除了mkfifo命令外,mknod命令也可以用来创建命名管道,其用法如下所示:


        $ mknod cmd_pipe p




        该命令执行后,将在当前目录下创建一个命名管道cmd_pipe,p用于指出建立的是命名管道。


     


     


     


    1、 管道概述及相关API应用


    1.1 管道相关的关键概念


    管道是Linux支持的最初Unix IPC形式之一,具有以下特点:


    管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
    只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
    单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
    数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
    1.2管道的创建:


    #include <unistd.h>
    int pipe(int fd[2])


    该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。


    1.3管道的读写规则:


    管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。


    从管道中读取数据:


    如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;
    当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据量)。注:(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF至少为512字节,red hat 7.2中为4096)。
    关于管道的读规则验证:


     /**************
     * readtest.c *
     **************/
    #include <unistd.h>
    #include <sys/types.h>
    #include <errno.h>
    main()
    {
    int pipe_fd[2];
    pid_t pid;
    char r_buf[100];
    char w_buf[4];
    char* p_wbuf;
    int r_num;
    int cmd;

    memset(r_buf,0,sizeof(r_buf));
    memset(w_buf,0,sizeof(r_buf));
    p_wbuf=w_buf;
    if(pipe(pipe_fd)<0)
    {
    printf("pipe create error\n");
    return -1;
    }

    if((pid=fork())==0)
    {
    printf("\n");
    close(pipe_fd[1]);
    sleep(3);//确保父进程关闭写端
       r_num=read(pipe_fd[0],r_buf,100);
    printf( "read num is %d   the data read from the pipe is %d\n",r_num,atoi(r_buf));

    close(pipe_fd[0]);
    exit();
    }
    else if(pid>0)
    {
    close(pipe_fd[0]);//read
    strcpy(w_buf,"111");
    if(write(pipe_fd[1],w_buf,4)!=-1)
    printf("parent write over\n");
    close(pipe_fd[1]);//write
    printf("parent close fd[1] over\n");
    sleep(10);
    }
    }
     /**************************************************
     * 程序输出结果:
     * parent write over
     * parent close fd[1] over
     * read num is 4   the data read from the pipe is 111
     * 附加结论:
     * 管道写端关闭后,写入的数据将一直存在,直到读出为止.
     ****************************************************/ 
     


    向管道中写入数据:


    向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。
    注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。
    对管道的写规则的验证1:写端对读端存在的依赖性


    #include <unistd.h>
    #include <sys/types.h>
    main()
    {
    int pipe_fd[2];
    pid_t pid;
    char r_buf[4];
    char* w_buf;
    int writenum;
    int cmd;

    memset(r_buf,0,sizeof(r_buf));
    if(pipe(pipe_fd)<0)
    {
    printf("pipe create error\n");
    return -1;
    }

    if((pid=fork())==0)
    {
    close(pipe_fd[0]);
    close(pipe_fd[1]);
    sleep(10);
    exit();
    }
    else if(pid>0)
    {
    sleep(1);  //等待子进程完成关闭读端的操作
    close(pipe_fd[0]);//write
    w_buf="111";
    if((writenum=write(pipe_fd[1],w_buf,4))==-1)
    printf("write to pipe error\n");
    else
    printf("the bytes write to pipe is %d \n", writenum);

    close(pipe_fd[1]);
    }
    }


    则输出结果为: Broken pipe,原因就是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进程中保留读端,即在写完pipe后,再关闭父进程的读端,也会正常写入pipe,读者可自己验证一下该结论。因此,在向管道写入数据时,至少应该存在某一个进程,其中管道读端没有被关闭,否则就会出现上述错误(管道断裂,进程收到了SIGPIPE信号,默认动作是进程终止)


    对管道的写规则的验证2:linux不保证写管道的原子性验证


    #include <unistd.h>
    #include <sys/types.h>
    #include <errno.h>
    main(int argc,char**argv)
    {
    int pipe_fd[2];
    pid_t pid;
    char r_buf[4096];
    char w_buf[4096*2];
    int writenum;
    int rnum;
    memset(r_buf,0,sizeof(r_buf));
    if(pipe(pipe_fd)<0)
    {
    printf("pipe create error\n");
    return -1;
    }

    if((pid=fork())==0)
    {
    close(pipe_fd[1]);
    while(1)
    {
    sleep(1);
    rnum=read(pipe_fd[0],r_buf,1000);
    printf("child: readnum is %d\n",rnum);
    }
    close(pipe_fd[0]);

    exit();
    }
    else if(pid>0)
    {
    close(pipe_fd[0]);//write
    memset(r_buf,0,sizeof(r_buf));
    if((writenum=write(pipe_fd[1],w_buf,1024))==-1)
    printf("write to pipe error\n");
    else
    printf("the bytes write to pipe is %d \n", writenum);
    writenum=write(pipe_fd[1],w_buf,4096);
    close(pipe_fd[1]);
    }
    }
    输出结果:
    the bytes write to pipe 1000
    the bytes write to pipe 1000  //注意,此行输出说明了写入的非原子性
    the bytes write to pipe 1000
    the bytes write to pipe 1000
    the bytes write to pipe 1000
    the bytes write to pipe 120  //注意,此行输出说明了写入的非原子性
    the bytes write to pipe 0
    the bytes write to pipe 0
    ......


    结论:


    写入数目小于4096时写入是非原子的! 
    如果把父进程中的两次写入字节数都改为5000,则很容易得出下面结论: 
    写入管道的数据量大于4096字节时,缓冲区的空闲空间将被写入数据(补齐),直到写完所有数据为止,如果没有进程读数据,则一直阻塞。


    1.4管道应用实例:


    实例一:用于shell


    管道可用于输入输出重定向,它将一个命令的输出直接定向到另一个命令的输入。比如,当在某个shell程序(Bourne shell或C shell等)键入who│wc -l后,相应shell程序将创建who以及wc两个进程和这两个进程间的管道。考虑下面的命令行:


    $kill -l 运行结果见 附一。


    $kill -l | grep SIGRTMIN 运行结果如下:


    30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1
    34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5
    38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9
    42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13
    46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14


    实例二:用于具有亲缘关系的进程间通信


    下面例子给出了管道的具体应用,父进程通过管道发送一些命令给子进程,子进程解析命令,并根据命令作相应处理。


    #include <unistd.h>
    #include <sys/types.h>
    main()
    {
    int pipe_fd[2];
    pid_t pid;
    char r_buf[4];
    char** w_buf[256];
    int childexit=0;
    int i;
    int cmd;

    memset(r_buf,0,sizeof(r_buf));
    if(pipe(pipe_fd)<0)
    {
    printf("pipe create error\n");
    return -1;
    }
    if((pid=fork())==0)
    //子进程:解析从管道中获取的命令,并作相应的处理
    {
    printf("\n");
    close(pipe_fd[1]);
    sleep(2);

    while(!childexit)
    {
    read(pipe_fd[0],r_buf,4);
    cmd=atoi(r_buf);
    if(cmd==0)
    {
    printf("child: receive command from parent over\n now child process exit\n");
    childexit=1;
    }

          else if(handle_cmd(cmd)!=0)
    return;
    sleep(1);
    }
    close(pipe_fd[0]);
    exit();
    }
    else if(pid>0)
    //parent: send commands to child
    {
    close(pipe_fd[0]);
    w_buf[0]="003";
    w_buf[1]="005";
    w_buf[2]="777";
    w_buf[3]="000";
    for(i=0;i<4;i++)
    write(pipe_fd[1],w_buf[i],4);
    close(pipe_fd[1]);
    }
    }
    //下面是子进程的命令处理函数(特定于应用):
    int handle_cmd(int cmd)
    {
    if((cmd<0)||(cmd>256))
    //suppose child only support 256 commands
    {
    printf("child: invalid command \n");
    return -1;
    }
    printf("child: the cmd from parent is %d\n", cmd);
    return 0;
    }


    1.5管道的局限性


    管道的主要局限性正体现在它的特点上:


    只支持单向数据流;
    只能用于具有亲缘关系的进程之间;
    没有名字;
    管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
    管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;
    回页首


    2、 有名管道概述及相关API应用


    2.1 有名管道相关的关键概念


    管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。


    2.2有名管道的创建


    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char * pathname, mode_t mode)


    该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如close、read、write等等。


    2.3有名管道的打开规则


    有名管道比管道多了一个打开操作:open。


    FIFO的打开规则:


    如果当前打开操作是为读而打开FIFO时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志);或者,成功返回(当前打开操作没有设置阻塞标志)。


    如果当前打开操作是为写而打开FIFO时,如果已经有相应进程为读而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。


    对打开规则的验证参见 附2。


    2.4有名管道的读写规则


    从FIFO中读取数据:


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


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


    向FIFO中写入数据:


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


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


    当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。
    当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。
    对于没有设置阻塞标志的写操作:


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


    下面提供了两个对FIFO的读写程序,适当调节程序中的很少地方或者程序的命令行参数就可以对各种FIFO读写规则进行验证。




    程序1:写FIFO的程序
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #define FIFO_SERVER "/tmp/fifoserver"
    main(int argc,char** argv)
    //参数为即将写入的字节数
    {
    int fd;
    char w_buf[4096*2];
    int real_wnum;
    memset(w_buf,0,4096*2);
    if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
    printf("cannot create fifoserver\n");
    if(fd==-1)
    if(errno==ENXIO)
    printf("open error; no reading process\n");

          fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);
    //设置非阻塞标志
    //fd=open(FIFO_SERVER,O_WRONLY,0);
    //设置阻塞标志
    real_wnum=write(fd,w_buf,2048);
    if(real_wnum==-1)
    {
    if(errno==EAGAIN)
    printf("write to fifo error; try later\n");
    }
    else 
    printf("real write num is %d\n",real_wnum);
    real_wnum=write(fd,w_buf,5000);
    //5000用于测试写入字节大于4096时的非原子性
    //real_wnum=write(fd,w_buf,4096);
    //4096用于测试写入字节不大于4096时的原子性

    if(real_wnum==-1)
    if(errno==EAGAIN)
    printf("try later\n");
    }




    程序2:与程序1一起测试写FIFO的规则,第一个命令行参数是请求从FIFO读出的字节数
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #define FIFO_SERVER "/tmp/fifoserver"
    main(int argc,char** argv)
    {
    char r_buf[4096*2];
    int  fd;
    int  r_size;
    int  ret_size;
    r_size=atoi(argv[1]);
    printf("requred real read bytes %d\n",r_size);
    memset(r_buf,0,sizeof(r_buf));
    fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0);
    //fd=open(FIFO_SERVER,O_RDONLY,0);
    //在此处可以把读程序编译成两个不同版本:阻塞版本及非阻塞版本
    if(fd==-1)
    {
    printf("open %s for read error\n");
    exit();
    }
    while(1)
    {

    memset(r_buf,0,sizeof(r_buf));
    ret_size=read(fd,r_buf,r_size);
    if(ret_size==-1)
    if(errno==EAGAIN)
    printf("no data avlaible\n");
    printf("real read bytes %d\n",ret_size);
    sleep(1);
    }
    pause();
    unlink(FIFO_SERVER);
    }


    程序应用说明:


    把读程序编译成两个不同版本:


    阻塞读版本:br
    以及非阻塞读版本nbr
    把写程序编译成两个四个版本:


    非阻塞且请求写的字节数大于PIPE_BUF版本:nbwg
    非阻塞且请求写的字节数不大于PIPE_BUF版本:版本nbw
    阻塞且请求写的字节数大于PIPE_BUF版本:bwg
    阻塞且请求写的字节数不大于PIPE_BUF版本:版本bw
    下面将使用br、nbr、w代替相应程序中的阻塞读、非阻塞读


    验证阻塞写操作:


    当请求写入的数据量大于PIPE_BUF时的非原子性:
    nbr 1000
    bwg
    当请求写入的数据量不大于PIPE_BUF时的原子性:
    nbr 1000
    bw
    验证非阻塞写操作:


    当请求写入的数据量大于PIPE_BUF时的非原子性:
    nbr 1000
    nbwg
    请求写入的数据量不大于PIPE_BUF时的原子性:
    nbr 1000
    nbw
    不管写打开的阻塞标志是否设置,在请求写入的字节数大于4096时,都不保证写入的原子性。但二者有本质区别:


    对于阻塞写来说,写操作在写满FIFO的空闲区域后,会一直等待,直到写完所有数据为止,请求写入的数据最终都会写入FIFO;


    而非阻塞写则在写满FIFO的空闲区域后,就返回(实际写入的字节数),所以有些数据最终不能够写入。


    对于读操作的验证则比较简单,不再讨论。


    2.5有名管道应用实例


    在验证了相应的读写规则后,应用实例似乎就没有必要了。


    回页首


    小结:


    管道常用于两个方面:(1)在shell中时常会用到管道(作为输入输入的重定向),在这种应用方式下,管道的创建对于用户来说是透明的;(2)用于具有亲缘关系的进程间通信,用户自己创建管道,并完成读写操作。


    FIFO可以说是管道的推广,克服了管道无名字的限制,使得无亲缘关系的进程同样可以采用先进先出的通信机制进行通信。


    管道和FIFO的数据是字节流,应用程序之间必须事先确定特定的传输"协议",采用传播具有特定意义的消息。


    要灵活应用管道及FIFO,理解它们的读写规则是关键。


    附1:kill -l 的运行结果,显示了当前系统支持的所有信号:


    1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
    5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
    9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
    13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
    18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
    22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
    26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
    30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1
    34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5
    38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9
    42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13
    46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14
    50) SIGRTMAX-13 51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10
    54) SIGRTMAX-9 55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6
    58) SIGRTMAX-5 59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2
    62) SIGRTMAX-1 63) SIGRTMAX


    除了在此处用来说明管道应用外,接下来的专题还要对这些信号分类讨论。


    附2:对FIFO打开规则的验证(主要验证写打开对读打开的依赖性)


    #include <sys/types.h>
    #include <sys/stat.h>
    #include <errno.h>
    #include <fcntl.h>
    #define FIFO_SERVER "/tmp/fifoserver"
    int handle_client(char*);
    main(int argc,char** argv)
    {
    int r_rd;
    int w_fd;
    pid_t pid;
    if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
    printf("cannot create fifoserver\n");
    handle_client(FIFO_SERVER);

    }
    int handle_client(char* arg)
    {
    int ret;
    ret=w_open(arg);
    switch(ret)
    {
    case 0:
    {
    printf("open %s error\n",arg);
    printf("no process has the fifo open for reading\n");
    return -1;
    }
    case -1:
    {
    printf("something wrong with open the fifo except for ENXIO");
    return -1;
    }
    case 1:
    {
    printf("open server ok\n");
    return 1;
    }
    default:
    {
    printf("w_no_r return ----\n");
    return 0;
    }
    }
    unlink(FIFO_SERVER);
    }
    int w_open(char*arg)
    //0  open error for no reading
    //-1 open error for other reasons
    //1  open ok
    {
    if(open(arg,O_WRONLY|O_NONBLOCK,0)==-1)
    { if(errno==ENXIO)
    {
    return 0;
    }
    else
    return -1;
    }
    return 1;

    }




    参考资料


    UNIX网络编程第二卷:进程间通信,作者:W.Richard Stevens,译者:杨继张,清华大学出版社。丰富的UNIX进程间通信实例及分析,对Linux环境下的程序开发有极大的启发意义。


    linux内核源代码情景分析(上、下),毛德操、胡希明著,浙江大学出版社,当要验证某个结论、想法时,最好的参考资料;


    UNIX环境高级编程,作者:W.Richard Stevens,译者:尤晋元等,机械工业出版社。具有丰富的编程实例,以及关键函数伴随Unix的发展历程。


    http://www.linux.org.tw/CLDP/gb/Secure-Programs-HOWTO/x346.html 点明linux下sigaction的实现基础,linux源码../kernel/signal.c更说明了问题;


    pipe手册,最直接而可靠的参考资料


    fifo手册,最直接而可靠的参考资料


     


    mkfifo(建立实名管道)
    相关函数
        pipe,popen,open,umask
    表头文件
        #include<sys/types.h>
        #include<sys/stat.h>
    定义函数
        int mkfifo(const char * pathname,mode_t mode);
    函数说明
        mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此 umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开 FIFO文件时,O_NONBLOCK旗标会有影响
        1、当使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。
        2、没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
    返回值
        若成功则返回0,否则返回-1,错误原因存于errno中。
    错误代码
        EACCESS 参数pathname所指定的目录路径无可执行的权限
        EEXIST 参数pathname所指定的文件已存在。
        ENAMETOOLONG 参数pathname的路径名称太长。
        ENOENT 参数pathname包含的目录不存在
        ENOSPC 文件系统的剩余空间不足
        ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。
        EROFS 参数pathname指定的文件存在于只读文件系统内。
       
    示例1:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>


    int main(void)
    {
        char buf[80];
        int fd;
        unlink( "zieckey_fifo" );
        mkfifo( "zieckey_fifo", 0777 );
       
        if ( fork() > 0 )
        {
            char s[] = "Hello!\n";
            fd = open( "zieckey_fifo", O_WRONLY );
            write( fd, s, sizeof(s) );
            //close( fd );
        }
        else
        {
            fd = open( "zieckey_fifo", O_RDONLY );
            read( fd, buf, sizeof(buf) );
            printf("The message from the pipe is:%s\n", buf );
            //close( fd );
        }
       
        return 0;
    }
    执行
        hello!
       
    示例2:   
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <errno.h>


    int main( int argc, char **argv )
    {
        mode_t mode = 0666;
        if ( argc !=2 )
        {
            printf( "Usage:[%s] fifo_filename\n", argv[0] );
            return -1;
        }
       
        if (mkfifo( argv[1], mode)<0 )
        {
            perror( "mkfifo");
            return -1;
        }
       
        return 0;
    }   
     ***************************************************************************************


    最近做的项目遇到一个问题:把播放器模块和UI模块整合成一个可执行程序,整合好后,一运行报出一个运行时错误,什么free一个地址出错了。这种问题是内存操作引起的,很难找出原因,而且这问题也不知道是UI模块还是播放器模块引起的,真是摸不着头脑。


    后来想想,把播放器编译成一个单独的可执行程序,UI也是单独的可执行程序,然后两者之间通过管道来实现进程间的通信。我使用的是命名管道,其实命名管道的创建和使用也不算太难:


    1、mkfifo创建一个管道,需要加一些创建标志,如O_CREAT等;


    2、使用open函数来获取管道描述符,这个关键点也是设置标志,如O_NONBLOCK,O_RDONLY, O_WRONLY等。


    3、然后在一个进程中使用write进行写,在另外一个进程中使用read进行读。这样就构造了一个单双工的通道。可以再创建一个管道来进行反向通信,从而实现双向通信。


    4、退出时使用unlink把管道文件删除掉。


    大概的步骤就是这样,关键是根据需要创建合适的通讯模式。


    注意:


    我在open的时候使用了O_NONBLOCK | WRONLY标志,然后出错了,返回-1。后来查看errno才知道,使用了O_NONBLOCK标志,必须先有进程以读的方式打开这个管道,才能以O_NONBLOCK | WRONLY标志来打开这个管道。


     






     


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


    目录 [隐藏]
    FIFO(命名管道)概述
    mkfifo函数
    命名管道读写规则
    从FIFO中读取数据
    从FIFO中写入数据
    FIFO示例
    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


    #include<stdlib.h>
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    int main()
    {
            int res = mkfifo("/tmp/my_fifo", 0777);
            if(res == 0)
            {
                    printf("FIFO created\n");
            }
            exit(EXIT_SUCCESS);
    }
    使用FIFO


    #include<errno.h>
    #include<sys/stat.h>
    #include<fcntl.h>


    FIFO "/tmp/my_fifo"
    //本程序从一个FIFO读数据,并把读到的数据打印到标准输出
    //如果读到字符“Q”,则退出
    int main(int argc, char** argv)
    {
            char buf_r[100];
            int fd;
            int nread;
            if((mkfifo(FIFO, O_CREAT) < 0) && (errno != EEXIST))
            {
                    printf("不能创建FIFO\n");
                    exit(1);
            }


            printf("准备读取数据\n");
            fd = open(FIFO, O_RDONLY, 0);
            if(fd == -1)
            {
                    perror("打开FIFO");
                    exit(1);
            }


            while(1)
            {
                    if((nread = read(fd, buf_r, 100)) == -1)
                    {
                            if(errno == EAGAIN) printf("没有数据\n");
                    }


                    //假设取到Q的时候退出
                    if(buf_r[0]=='Q') break;


                    buf_r[nread]=0;
                    printf("从FIFO读取的数据为:%s\n", buf_r);
                    sleep(1);
            }



    展开全文
  • mkfifo函数使用

    万次阅读 2017-06-18 20:46:37
    mkfifo(建立实名管道) 相关函数  pipe,popen,open,umask 表头文件  #include  #include 定义函数  int mkfifo(const char * pathname,mode_t mode); 函数说明  mkfifo()会依参数pathname建立特殊...
  • mkfifo 命令

    2012-08-28 22:40:33
    Create named pipes (FIFOs) with the given NAMEs. ...Mkfifo test.log 终端1: ping 119.75.217.56 >test.log 终端2: Cat test.log 演示2: Mkfifo –m 644 test2.log Mkfifo –m g-w o-r...
  • pipe、mkfifo

    2018-10-11 13:47:25
    mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名管道。 前边讲的那些管道都没有名字,因此它们被称为匿名管道,或简称管道。对文件系统来说, 匿名管道是不可见的,它的作用仅限于在...
  • # mkfifo myfifo# pingedu.cn >> myfifo 另开一个终端:# cat myfifo 看到效果了吧 mkfifo 命令 ...根据指定的顺序,mkfifo 命令创建由 File 参数指定的 FIFO 特别文件。如果没有指定 -m ...
  • mkfifo-建立命名管道

    2018-08-22 20:58:48
    mkfifo是一个建立实名管道的函数 创建命名管道的方法为:mkfifo pipe。 这样就能创建一个命名的管道pipe。 表头文件  #include&lt;sys/types.h&gt;  #include&lt;sys/stat.h&gt; 定义函数  ...
  • mkfifo函数解析及应用

    2019-09-24 12:06:31
    Int mkfifo(const char* pathname,mode_t mode); A:创建管道(mkfifo)-> 打开管道(open)-> 读写数据(read/write)-> 关闭管道(close) -> 删除管道(unlink) B:打开管道 -> 读写数据 -> ...
  • 测试代码:mkfifo

    2021-02-01 13:55:39
    int mk = mkfifo(“1.p”,0640); if( mk < 0){ perror(“mkfifo”); //return -1; } int fd = open(“1.p”,O_RDWR); if(fd < 0){ perror(“openfd”); } #if 0 pid_t pid; if((pid = fork())<0) { perror...
  • 有名管道mkfifo

    2017-04-14 17:16:00
    int mkfifo(const char *pathname, mode_t mode); int mknod(const char *pathname, mode_t mode, dev_t dev); 管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信。 在有名管道(named pipe...
  • mkfifo,scriptfifo

    2015-02-15 11:22:04
    有关mkfifo,scriptfifo实现的两个终端屏幕一致性输出terminal1:mkfifo scriptfifoterminal2:cat scriptfifoterminal1:script -f scriptfifocommands 转载于:https://blog.51cto.com/8335914/1614549...
  • 使用mkfifo及fgets实现写管道用来处理外部debug命令 例如: echo encyuv -i /home/test.yuv -w 1920 -h 1080 &gt; debugNode debugNode即为mkfifo创建的实名管道。   下面介绍一个简单的示例程序: #...
  • pipe popen mkfifo

    2014-08-20 19:25:53
    mkfifo,popen,read,write,fork 表头文件 #include 定义函数 int pipe(int filedes[2]); 函数说明 pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,...
  • Linux_ mkfifo 命名管道 操作
  • linux mkfifo管道

    2012-12-25 09:31:48
    mkfifo是可以产生一个管道,其中一个进程往里面写数据,另外一个进程可以读这个管道中的数据。 可以用于进程间的通信。 例如: mkfifo -m 777 myfifo cat 3.sh > myfifo & [1] 7427 wc -l < ...
  • Linux在NodeJS中命名管道(mkfifo) npm install named-pipe 该库创建Linux管道,而无需使用C ++绑定并通过Shell执行。 依存关系 没有任何! 您的外壳需要支持mkfifo 。 在外壳中尝试mkfifo --help ,看看是否可以...
  • mkfifo shell 并行

    2013-01-21 10:10:36
    #!/bin/sh mkfifo tmp.$$ exec 4<>tmp.$$ rm -rf tmp.$$ { count=4 while [ $count -gt 0 ] do echo let count=count-1 done } >&4 f...
  • shell mkfifo 阻塞式管道

    千次阅读 2015-09-25 10:52:24
    MKFIFO Section: User Commands (1) Updated: 1998年11月 Index Return to Main Contents NAME(名称) mkfifo - 创建FIFO(命名管道) SYNOPSIS(总览) mkfifo [options] file... POSIX options(选项):...
  • Linux_ mkfifo 命名管道 操作demo

    千次阅读 2016-03-31 22:36:59
    Linux_ mkfifo 命名管道 操作demo

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,843
精华内容 5,937
关键字:

mkfifo