• 《Linux应用进程间通信(二) — 命名管道》


    命名管道的主要用途:不相关的进程之间交换数据。

    命令行上创建命名管道:

    $ mkfifo filename

     程序中创建命名管道:

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

    备注:#include <sys/types.h>是Unix/Linux系统的基本系统数据类型的头文件,含有Size_t,time_t,pid_t等类型。

       #include<sys/stat.h>是Unix/Linux系统定义文件状态所在的伪标准头文件。

    例程:创建一个FIFO命名管道

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    int main(int argc, char *argv[])
    {
        int res;
    
        res = mkfifo("./FIFO", 0777);
        if(res == 0)
        {
            printf("FIFO created
    ");
        }
    
        exit(EXIT_SUCCESS);
    
    }

    备注:文件权限方面的知识有点模糊,需要回顾。

    $ ls -lF(F选项会在显示目录条目时,在目录后加一个符号“/”表示文件夹 “|”表示管道)
    prwxr-xr-x 1 root root 0 12月 17 17:02 FIFO|

    创建出来的FIFO管道如上图所示,其中第一个字符p表示这是一个管道,其中最后一个|符号是由ls命令的-F选项所添加,也表示它是一个管道。

    FIFO是以命名文件的形式存在,而不是打开的文件描述符,所以在对它进行读写操作之前必须先打开它。而且,对于FIFO来说,传递给open函数的第一个参数一定是一个FIFO的路径名,而不是一个文件名。

    使用open打开FIFO文件

    1.FIFO命名管道不能以O_RDWR的模式打开,会产生二义性。(通常使用FIFO只是为了单向传递数据)

    2.如果确定需要程序之间双向传递数据。①最好使用一对FIFO或者管道,一个方向使用一个②采用先关闭再重新打开FIFO的方法来明确地改变数据流的去向(不常用)。

    3.打开FIFO文件和打开普通文件的另一点区别是:对open_flag(open的第二个参数)的O_NONBLOCK的用法。

    • open(const char *path, O_RDONLY);

    在这种情况下,open调用将阻塞,除非有一个进程以写方式打开一个FIFO,否则它是不会返回。

    • open(const char *path, O_RDONLY | O_NONBLOCK);

    即使没有其他进程以写方式打开FIFO,open调用也会成功并且立即返回。

    • open(const char *path, WRONLY);

    在这种情况下,open调用将阻塞,直到有一个进程以读方式打开进程。

    • open(const char *path,  WRONLY | O_NONBLOCK);

    这个函数调用总是立刻返回,但如果没有进程以读方式打开FIFO文件,open调用将返回一个错误-1并且FIFO也不会被打开。如果确实有一个进程以读方式打开FIFO文件,那么我们就我再可以通过它返回的文件描述符对这个FIFO文件进行写操作。

      注意:由以上可知,必须先有进程以读方式打开FIFO文件,然后再有进程以写方式打开FIFO文件。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <string.h> /* using string */
    #include <fcntl.h> /* O_RDONLY in this file */
    
    #define FILE_NAME "/home/test/readfifo"
    
    int main(int argc, char *argv[])
    {
        int res;
        
      /* 确保文件存在 */ if(access(FILE_NAME, F_OK) == -1) { res = mkfifo(FILE_NAME, 0777); if(res != 0) { printf("the fifo file could not create "); exit(EXIT_FAILURE); } } printf("read fifo file create successfull "); open(FILE_NAME, O_RDONLY | O_NONBLOCK); printf("open the read fifo file is success "); exit(EXIT_SUCCESS); }

    备注:string.h在使用到字符数组时需要使用。

            fcntl.h是unix标准中通用的头文件,其中包含相关函数有open,fcntl,shutdown,unlink,fclose等。与unistd.h相比,后者定义了更多的函数原型。

    在open的函数调用中,如果是非阻塞。

    read fifo file create successfull 
    
    open the read fifo file is success 

    在open的函数调用中,如果是阻塞,即没有使用O_NONBLOCK

    read fifo file create successfull 

    就会阻塞在open函数上,然后等待写进程打开这个函数,然后才会返回。

     注意:Linux中进程被阻塞时,并不消耗CPU资源。

    对FIFO进行读写操作

    如果在open函数使用了O_NONBLOCK模式,会影响到对FIFO的read和write调用。

    • 对一个空的、阻塞的FIFO(即没有用O_NONBLOCK标志打开的)的read调用将等待,直到有数据可以读时才继续执行。
    • 对一个空的、非阻塞的FIFO的read调用将立刻返回0字节。
    • 对一个完全阻塞FIFO的write调用将等待,直到数据可以被写入才继续执行,如果FIFO不能接受所有写入数据,将按照下面的规则执行:①如果请求写入的数据长度小于等于PIPE_BUF字节,调用失败,数据不能写入。(表示有空间,但是不能写入,出现问题)。②如果请求写入的数据的长度大于PIPE_BUF字节,将写入部分数据,返回实际写入的字节数,返回值也可能是0(表示只是FIFO的空间不足,先写入部分数据)。

    注意:PIPE_BUF是系统对FIFO的一个数据长度的限制,通常在头文件limits.h可以找到它,通常值为4096字节,也有特例。系统规定:在一个以O_WRONLY方式(即阻塞方式)打开的FIFO中,如果写入的数据长度小于等于PIPE_BUF,要么全部一次性写入,要么一个字节也不写入。

    基于“注意”中的描述,如果出现一种情况:多个程序向一个FIFO中写入数据的时候,为了保证这些写入的数据不会相互交错重叠,那么就要求每次写入的数据长度要小于等于PIPE_BUF字节。

  • 相关阅读:
    洛谷-P1496 火烧赤壁
    洛谷-P5638 【CSGRound2】光骓者的荣耀
    Java多线程实现
    linux安装mysql 8的完整过程
    tomcat安装
    C#之Null
    JToken
    初识算法之线性表---双向列表
    初识算法之线性表---链表定义/结构(2)
    初识算法之线性表---链表定义/结构(1)
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/13143656.html
Copyright © 2020-2023  润新知