进程通信之二FIFO

简介

FIFO突破通常管道无法进行无关进程之间的通信的限制,使得同一主机内的所有的进程都可以通信。FIFO是一个文件类型,stat结构中st_mode指明一个文件结点是不是一个FIFO,可以使用宏S_ISFIFO来测试这一点。当一个FIFO存在于文件系统里时,我们只需要在想进行通信的进程内打开这个文件就可以了。当然FIFO作为一个特殊的文件,它有一些不同普通文件特性,下面会详细详述它的读写规则,这些相对精通文件来有一定的区别。我们可以使用open、read、write来操作FIFO文件,从而实现进程间通信的目的。在shell环境下,也可以直接使用FIFO,这时往往与重写向有一些关联,一般系统都提供mkfifo实用程序来创建一个FIFO文件,这个程序实际上使用mkfifo系统调用来完成这个事。

示例


/*
 * =====================================================================================
 *
 *       Filename:  fifo.c
 *
 *    Description:  IPC using fifo
 *
 *        Version:  1.0
 *        Created:  2012年02月17日 10时57分30秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  chn89, chn89@126.com
 *   Organization:  
 *
 * =====================================================================================
 */
#include    <stdlib.h>
#include    <stdio.h>
#include    <string.h>
#include    <sys/types.h>
#include    <sys/stat.h>
#include    <fcntl.h>

#define    FIFO    "fifo_tmp"

int
main(void)
{
    int        fdread, fdwrite;
    char buf[256];

    unlink(FIFO);
    if (mkfifo(FIFO, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) < 0)
        printf("mkfifo error");

    if ( (fdread = open(FIFO, O_RDONLY | O_NONBLOCK)) < 0)
        printf("open error for reading\n");
    if ( (fdwrite = open(FIFO, O_WRONLY)) < 0)
        printf("open error for writing\n");
    write(fdwrite,"fsfd",4);
    read(fdread,buf,256);
    printf("%s\n",buf);
    exit(0);
}
注意事项:


(1)管道数据的FIFO处理方式,首先放入管道的数据,在端口首先被读出
(2)管道数据的不可再现性,已读取的数据在管道里消失,不能再读
(3)管道长度的有限性
(4)SIGPIPE信号 如果一个进程试图写入到一个没有读取到进程的管道中哦你,系统内核产生SIGPIPE信号


<think>我们参考了用户提供的多个引用,特别是引用[3]和[5]中提到了FIFO管道的使用。引用[3]提供了FIFO管道在无亲缘关系进程通信的编程思路和部分代码片段。引用[4]和[5]提供了管道(匿名管道)的示例,但用户明确要求FIFO(命名管道)的演示代码。因此,我们将重点根据引用[3]的内容,提供一个完整的FIFO管道通信示例。FIFO管道(命名管道)与匿名管道的区别在于,FIFO存在于文件系统中,可以通过路径名进行访问,因此可以用于无亲缘关系的进程通信。根据引用[3]的描述,我们可以创建两个FIFO管道来实现双向通信(半双工)。这里我们展示两个进程进程A和进程B,它们之间通过两个FIFO文件进行双向通信。步骤:1.创建两个FIFO文件,例如fifo0和fifo1。2.进程A:打开fifo0用于读取,打开fifo1用于写入。3.进程B:打开fifo0用于写入,打开fifo1用于读取。4.这样,进程A可以通过fifo1向进程B发送数据,而进程B可以通过fifo0向进程A发送数据。注意:在实际编程中,需要确保FIFO文件已经存在(可以使用mkfifo函数创建),并且注意打开FIFO的读写端会阻塞直到另一端也被打开。下面是一个使用C语言的示例代码,包括两个程序:fifo_a.c(进程A)和fifo_b.c(进程B)。由于代码较长,我们将分开编写。首先,我们创建两个FIFO文件,可以通过命令行创建,也可以在程序中使用mkfifo函数创建。这里我们选择在程序中创建(注意需要检查文件是否已经存在,避免错误)。但是,引用[3]中提到了在创建FIFO使用mkfifo函数,并注意权限设置。为了简化,我们先在程序中创建FIFO文件,并在程序退出时删除它们(也可以不删除,但为了不留下垃圾文件,我们添加清理代码)。注意:在真实环境中可能需要考虑持久化或由外部管理FIFO文件。由于删除文件需要在两个进程中分别进行,但进程结束后文件可能仍会保留,所以我们可以使用信号处理函数来捕获退出信号并删除文件。然而,为了简单,我们这里不处理信号,而是建议手动删除或使用临时文件机制。另一种做法是:每次运行前检查并删除已有的FIFO文件,重新创建。下面我们开始编写代码:注意:我们使用两个FIFO文件:/tmp/fifo0和/tmp/fifo1。进程A(fifo_a.c):-创建FIFO文件(如果已经存在则跳过或删除重新创建)-打开fifo0的读端和fifo1的写端-然后从标准输入读取数据,通过fifo1发送给进程B,同时从fifo0读取进程B发来的数据并打印。进程B(fifo_b.c):-同样确保FIFO文件存在-打开fifo0的写端和fifo1的读端-从标准输入读取数据,通过fifo0发送给进程A,同时从fifo1读取进程A发来的数据并打印。但是,这里有一个问题:两个进程都需要同时监听标准输入和FIFO的读端。这需要使用多线程或非阻塞I/O或select/poll等。为了简化,我们让每个进程分别创建两个线程:一个线程负责从标准输入读取并发送,另一个线程负责从FIFO读取并打印。然而,引用[3]中的示例是单线程的,并且没有使用标准输入,而是固定发送字符串。为了简单演示,我们先做一个固定顺序的通信进程A先发送一个消息到进程B,然后进程B接收到后回复一个消息,进程A再接收。但这样无法同时进行双向通信。为了更贴近实际,我们使用多线程实现同时读写。由于用户可能要求简洁的示例,我们提供一个简化版本:一个进程只发送消息,另一个进程只接收消息,但这样是单向的。所以为了演示双向通信,我们每个进程都同时有发送和接收功能,并且使用多线程。以下是多线程版本的FIFO双向通信示例。注意:在多线程环境中使用FIFO管道需要注意同步和互斥,但这里我们只做简单演示。由于代码较长,我们将分别给出两个程序,并加以注释。进程A:</think> ### FIFO管道通信演示代码示例 FIFO(命名管道)是Linux进程通信的重要机制,特别适用于无亲缘关系进程通信。以下是一个完整的双向通信示例(基于引用[3]的实现思路): ```c /* fifo_a.c - 进程A示例 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #define FIFO0 "/tmp/fifo0" // A读B写的管道 #define FIFO1 "/tmp/fifo1" // A写B读的管道 int main() { char buf[100]; int fd0, fd1; // 创建FIFO管道(如果不存在) mkfifo(FIFO0, 0666); mkfifo(FIFO1, 0666); // 打开管道(O_RDWR避免阻塞) fd0 = open(FIFO0, O_RDONLY); // 管道0读端 fd1 = open(FIFO1, O_WRONLY); // 管道1写端 // 写入数据进程B char *msgA = "Message from Process A"; write(fd1, msgA, strlen(msgA)+1); // 从进程B读取数据 read(fd0, buf, sizeof(buf)); printf("A received: %s\n", buf); // 清理 close(fd0); close(fd1); unlink(FIFO0); unlink(FIFO1); return 0; } ``` ```c /* fifo_b.c - 进程B示例 */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #define FIFO0 "/tmp/fifo0" // B写A读的管道 #define FIFO1 "/tmp/fifo1" // B读A写的管道 int main() { char buf[100]; int fd0, fd1; // 打开管道 fd0 = open(FIFO0, O_WRONLY); // 管道0写端 fd1 = open(FIFO1, O_RDONLY); // 管道1读端 // 从进程A读取数据 read(fd1, buf, sizeof(buf)); printf("B received: %s\n", buf); // 回复数据进程A char *msgB = "Reply from Process B"; write(fd0, msgB, strlen(msgB)+1); // 清理 close(fd0); close(fd1); return 0; } ``` ### 关键实现说明(引用[3][^3]): 1. **双管道机制**:创建两条FIFO管道实现双向通信 - `fifo0`:A读端 → B写端 - `fifo1`:A写端 → B读端 2. **FIFO特性**: - 通过文件路径访问(`/tmp/fifo*`) - 使用`mkfifo()`创建,权限为0666 - 打开时使用阻塞模式(默认行为) 3. **运行方式**: ```bash # 终端1(进程A) gcc fifo_a.c -o fifo_a ./fifo_a # 终端2(进程B) gcc fifo_b.c -o fifo_b ./fifo_b ``` 4. **预期输出**: ``` B received: Message from Process A A received: Reply from Process B ``` ### 注意事项: 1. 打开顺序影响阻塞:读端会阻塞直到写端打开(反之亦然)[^3] 2. 通信流程:先创建管道 → 打开对应端口 → 读写操作 3. 退出处理:最后需要关闭文件描述符和删除管道文件 4. 无亲缘关系:两个进程可以完全独立启动(不同于匿名管道)[^1] 如果需要信号处理(如处理`SIGINT`退出信号),可参考引用[2]添加信号处理器[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值