• Linux进程间通信-FIFO(命名管道)


    本系列文章主要是学习记录Linux下进程间通信的方式。

    常用的进程间通信方式:管道、FIFO、消息队列、信号量以及共享存储。

    参考文档:《UNIX环境高级编程(第三版)》

    参考视频:Linux进程通信  推荐看看,老师讲得很不错

    Linux核心版本:2.6.32-431.el6.x86_64

    注:本文档只是简单介绍IPC,更详细的内容请查看参考文档和相应视频。

    本文介绍利用FIFO(命名管道)进行进程间的通信。

    1  介绍

    FIFO也称为命名管道。未命名的管道只能在两个相关的进程之间使用,而且这两个相关进程有一个共同的祖先进程。但是,FIFO可在不相关的进程间交换数据

    本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在。

    在文件系统中只有一个索引块存放文件的路径,没有数据块,所有数据存放在内核中。

    命令管道必须读和写同时打开,否则单独读或者单独写会引发阻塞

    2  函数原型

    1 #include <sys/types.h>
    2 #include <sys/stat.h>
    3 int mkfifo(const char *pathname, mode_t mode);
    4 int mkfifoat(int dirfd, const char *pathname, mode_t mode);
    5 说明:创建一个FIFO
    6 返回值:成功返回0;出错返回-17 参数[in]:mode参数和open参数相同;
    8 参数[in]:pathname文件路径名。
    9 参数[in]:dirfd打开目录的有效文件描述符,若pathname是绝对路径名,此参数被忽略;若是相对路径路径名,此参数是一个打开目录的有效文件描述符。

    3  操作

    创建FIFO时,要用open来打开它。当write一个没有进程为读而打开的FIFO时,会产生信号SIGPIPE;当某个FIFO的最后一个写进程关闭了该FIFO,则将为该FIFO的读进程产生一个文件结束标志。

    一旦已经用mkfifo创建了一个FIFO,就可用open打开它,一般的文件I/O函数(close、read、write、unlink等)。

    4  测试代码

     分别创建一个读和一个写进程,对同一个命令管道进行读写操作。

    读进程fifo_read.c:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 
     7 int main(int argc, char *argv[])
     8 {
     9     if (argc < 2) {
    10         printf("usage:%s fifo
    ", argv[0]);
    11         exit(1);
    12     }
    13     printf("open fifo read...
    ");
    14     int fd = open(argv[1], O_RDONLY);
    15     if (fd < 0) {
    16         perror("open error");
    17         exit(1);
    18     } else {
    19         printf("open file success: %d
    ", fd);
    20     }
    21     //从命名管道中读取数据
    22     char buf[512] = {0};
    23     while (read(fd, buf, sizeof(buf)) < 0) {
    24         perror("read error");
    25     }
    26     printf("%s
    ", buf);
    27     close(fd);
    28 
    29     return 0;
    30 }
    View Code

    写进程fifo_write.c:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <stdlib.h>
     6 #include <string.h>
     7 
     8 int main(int argc, char *argv[])
     9 {
    10     if (argc < 2) {
    11         printf("usage: %s fifo
    ", argv[0]);
    12         exit(1);
    13     }
    14     printf("open fifo write...
    ");
    15     int fd = open(argv[1], O_WRONLY);
    16     if (fd < 0) {
    17         perror("open error");
    18         exit(1);
    19     } else {
    20         printf("open fifo success: %d
    ", fd);
    21     }
    22     char *s = "123456789";
    23     size_t size = strlen(s);
    24     if (write(fd, s, size) != size) {
    25         perror("write error");
    26     }
    27     close(fd);
    28 
    29     return 0;
    30 }
    View Code

    测试步骤:

    1、先分别编译这两个程序:

    [root@192 ipc]# gcc -o bin/fifo_read fifo_read.c   

    [root@192 ipc]# gcc -o bin/fifo_write fifo_write.c 

    2、使用mkfifo创建一个命名管道:[root@192 ipc]# mkfifo s.pipe

    3、单独只执行其中的一个进程,会阻塞住:

     4、另外打开一个终端,执行写进程:

     这时读进程也得到了执行:

    5  匿名管道和命名管道读写的相同点

    (1)默认都是阻塞性读写;

    (2)阻塞不完整管道(有一端关闭)

    • 单纯读时,在所有数据被读取后,read返回0,以表示到达了文件尾部;
    • 单纯写时,则产生信号SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则write返回-1,同时errno设置为EPIPE。

    (3)阻塞完整管道(两端都开启)

    • 单纯读时,要么阻塞,要么读取到数据;
    • 单纯写时,写到管道满时会出错。

    (4)非阻塞不完整管道(有一端关闭)

    • 单纯读时直接报错;
    • 单纯写时,则产生信号SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则write返回-1,同时errno设置为EPIPE。

    (5)非阻塞完整管道(两端都开启)

    • 单纯读时直接报错;
    • 单纯写时,写到管道满时会报错。
  • 相关阅读:
    jQuery实现图片前进后退
    jQuery写日历
    python列表模拟栈
    python 列表去重
    Linux的文件系统
    新建vss数据库
    关于业务用例和系统用例
    从零开始使用Linux命令
    svn的安装与配置
    数塔 动态规划
  • 原文地址:https://www.cnblogs.com/mrlayfolk/p/13034404.html
Copyright © 2020-2023  润新知