Linux进程通信 | 管道与FIFO
Linux进程间通信通常使用的方式有很多种,其中比较常用的包括管道(pipe)和 FIFO(命名管道)。本文将介绍这两种通信方式的基本概念,并用C语言编写示例代码,来说明如何在两个进程之间使用这些IPC机制进行通信。
管道(pipe)
管道是一种半双工的通信方式,用于父进程和子进程之间的通信。在 Linux 中,管道是一种特殊的文件,有两个端点,一个读端和一个写端。管道的基本操作包括创建管道、关闭文件描述符、读取数据和写入数据等。
创建管道
在 Linux 中,我们可以使用 pipe() 系统调用来创建管道。pipe() 函数的原型如下:
#include <unistd.h>
int pipe(int pipefd[2]);
其中,pipefd 是一个数组,用于存储管道的读端和写端的文件描述符。pipe() 函数成功时返回 0,失败时返回 -1。
下面是一个创建管道的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pipefd[2];
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
printf("读端文件描述符:%d\n", pipefd[0]);
printf("写端文件描述符:%d\n", pipefd[1]);
exit(EXIT_SUCCESS);
}
- 编译并运行,打印如下
读端文件描述符:3
写端文件描述符:4
管道的读写
在使用管道进行通信时,父进程和子进程可以通过管道进行数据的读取和写入。在 C 语言中,我们可以使用 read()函数和 write() 函数来读取和写入数据。read() 函数用于从管道中读取数据,write() 函数用于向管道中写入数据,使用 close() 函数关闭文件描述符。在管道的使用中,我们应该在不需要的时候关闭管道的读端和写端,以避免资源浪费。
这三个函数的原型分别如下:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);
下面是一个父进程向子进程写入数据并读取返回结果的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#define BUF_SIZE 1024
int main()
{
int pipefd[2];
pid_t pid;
char buf[BUF_SIZE];
int status;
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) { // 子进程
// 从管道中读取数据
if (read(pipefd[0], buf, BUF_SIZE) == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("子进程收到消息:%s\n", buf);
// 发送消息给父进程
const char* message = "Hello, parent!";
if (write(pipefd[1], message, strlen(message) + 1) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
close(pipefd[1]); // 关闭写端
exit(EXIT_SUCCESS);
} else { // 父进程
// 发送消息给子进程
const char* message = "Hello, child!";
if (write(pipefd[1], message, strlen(message) + 1) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
// 等待子进程退出
wait(&status);
if (WIFEXITED(status)) {
printf("子进程退出,返回值:%d\n", WEXITSTATUS(status));
}
// 从管道中读取数据
if (read(pipefd[0], buf, BUF_SIZE) == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("父进程收到消息:%s\n", buf);
close(pipefd[0]); // 关闭读端
exit(EXIT_SUCCESS);
}
}
在这个示例代码中,父进程先向子进程发送一条消息,子进程收到消息后向父进程发送一条消息,并退出。父进程在等待子进程退出后再从管道中读取子进程发送的消息。
- 编译并运行,打印如下
子进程收到消息:Hello, child!
子进程退出,返回值:0
父进程收到消息:Hello, parent!
FIFO(命名管道)
FIFO(命名管道)是一种文件系统对象,与管道类似,也可以用于进程间通信。FIFO 是一种特殊类型的文件,它可以在文件系统中被创建,并且进程可以通过文件描述符来读取和写入数据。
与管道不同的是,FIFO 可以被多个进程打开,并且可以在文件系统中以路径的形式存在,因此不像管道那样只能在具有亲缘关系的进程之间使用。任何进程只要有相应的权限就可以打开 FIFO 并进行通信。
FIFO 的创建和使用
FIFO 的创建和使用也比较简单。首先需要使用 mkfifo() 函数创建 FIFO 文件,其原型如下
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
其中,pathname 是 FIFO 文件的路径名,mode 是文件的权限。
创建 FIFO 文件后,就可以像使用普通文件一样打开它,并使用 read() 和 write() 函数进行数据的读写。
下面是一个使用 FIFO 进行进程间通信的示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO_PATH "/tmp/myfifo"
#define BUF_SIZE 1024
int main()
{
int fd;
char buf[BUF_SIZE];
// 创建 FIFO 文件
if (mkfifo(FIFO_PATH, 0666) == -1) {
perror("mkfifo");
exit(EXIT_FAILURE);
}
// 打开 FIFO 文件
fd = open(FIFO_PATH, O_RDWR);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
// 向 FIFO 中写入数据
const char* message = "Hello, world!";
if (write(fd, message, strlen(message) + 1) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
// 从 FIFO 中读取数据
if (read(fd, buf, BUF_SIZE) == -1) {
perror("read");
exit(EXIT_FAILURE);
}
printf("收到消息:%s\n", buf);
// 关闭文件描述符并删除 FIFO 文件
close(fd);
if (unlink(FIFO_PATH) == -1) {
perror("unlink");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
在这个示例代码中,程序先创建了一个 FIFO 文件 /tmp/myfifo,然后打开该文件并向其中写入一条消息。接下来从 FIFO 文件中读取数据,并将其打印出来。最后关闭文件描述符并删除 FIFO 文件。
- 编译并运行,打印如下
收到消息:Hello, world!
小结
Linux 中管道和 FIFO 是进程间通信的重要方式。管道只能用于亲缘关系的进程间通信,而 FIFO 可以被多个进程打开,不受进程之间关系的限制。无论是管道还是 FIFO,它们的使用方式都与普通文件类似,需要使用文件描述符和 read()、write() 函数来进行数据的读写。
在使用管道和 FIFO 进行进程间通信时,需要注意以下几点:
- 管道和 FIFO 只能用于同一主机上的进程间通信,不能用于跨主机通信。
- 管道和 FIFO 的读写操作是阻塞的,这意味着当一个进程尝试从一个空管道或 FIFO 中读取数据时,它会被阻塞,直到有数据可用为止。同样,当一个进程尝试将数据写入一个满的管道或 FIFO 时,它也会被阻塞,直到有空闲空间为止。
- 在使用管道和 FIFO 进行进程间通信时,需要注意文件描述符的关闭顺序。
- 管道和 FIFO 只能传输字节流,不能传输其他类型的数据,如结构体或指针。
- 如果使用管道或 FIFO 进行进程间通信时,数据量较大,需要进行分段传输,否则可能会导致阻塞或缓冲区溢出等问题。
- 管道和 FIFO 都是单向的,如果需要双向通信,则需要建立两个管道或 FIFO。
以上,如果觉得对你有帮助,点个赞再走吧,这样@知微之见也有更新下去的动力!
也欢迎私信我,一起交流!
Linux进程通信 | 管道与FIFO的更多相关文章
- linux 进程通信 管道
1. 管道概述及相关API应用 1.1 管道相关的关键概念 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管 ...
- Linux进程通信——管道
管道(pipe)本质上是一种文件,管道通信本质上是通过读写文件通信,但是管道解决了文件的两个问题:限制管道大小,解决read()调用文件结束问题. 管道一个环形的缓冲区,通过两个进程以生产者/消费者的 ...
- Linux进程通信----匿名管道
Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...
- linux进程的管道通信
linux进程的管道通信 要求 编程实现进程的管道通信,掌握管道通信的同步和互斥机制. 相关函数 pipe管道 指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又名pipe文件.向管 ...
- Linux 进程通信(有名管道)
有名管道(FIFO) 有名管道是持久稳定的. 它们存在于文件系统中. FIFO比无名管道作用更大,因为他们能让无关联的进程之间交换数据. 管道文件一般用于交换数据. shell命令创建管道 一个she ...
- linux进程通信之管道
1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...
- Linux进程通信之匿名管道
进程间的通信方式 进程间的通信方式包括,管道.共享内存.信号.信号量.消息队列.套接字. 进程间通信的目的 进程间通信的主要目的是:数据传输.数据共享.事件通知.资源共享.进程控制等. 进程间通信之管 ...
- Linux 进程通信之管道
管道是单向的.先进先出的,它把一个进程的输出和还有一个进程的输入连接在一起.一个进程(写进程)在管道的尾部写入数据,还有一个进程(读进程)从管道的头部读出数据.数据被一个进程读出后,将被从管道中删除, ...
- linux进程通信之使用匿名管道进行父子进程通信
管道:是指用于连接一个读进程和一个写进程,以实现它们之间通信的共享文件,又称pipe文件. 管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起 ...
- linux进程间通信-有名管道(FIFO)
有名管道(FIFO) 命名管道也被称为FIFO文件,是一种特殊的文件.由于linux所有的事物都可以被视为文件,所以对命名管道的使用也就变得与文件操作非常统一. (1)创建命名管道 用如下两个函数中的 ...
随机推荐
- Listener refused the connection with the following error: ORA-12514
1.问题 在使用Oracle SQL Developer时,遇到以下问题: 状态: 失败 -测试失败: Listener refused the connection with the followi ...
- 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.12.18)
一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...
- GB18030-2022 标准学习
GB18030-2022 标准学习 下载 https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=A1931A578FE14957104988029B08 ...
- [转帖]备份与恢复工具 BR 简介
https://docs.pingcap.com/zh/tidb/v4.0/backup-and-restore-tool BR 全称为 Backup & Restore,是 TiDB 分布式 ...
- 【转帖】一道面试题:JVM老年代空间担保机制
面试问题 昨天面试的时候,面试官问的问题: 什么是老年代空间担保机制?担保的过程是什么? 老年代空间担保机制是谁给谁担保? 为什么要有老年代空间担保机制?或者说空间担保机制的目的是什么? 如果没有老年 ...
- 【转帖】【ethtool】ethtool 网卡诊断、调整工具、网卡性能优化| 解决丢包严重
目录 即看即用 详细信息 软件简介 安装 ethtool的使用 输出详解 其他指令 将 ethtool 设置永久保存 如何使用 ethtool 优化 Linux 虚拟机网卡性能 ethtool 解决网 ...
- [转帖]BF16 与 FP16 在模型上哪个精度更高呢
https://zhuanlan.zhihu.com/p/449345588 BF16 是对FP32单精度浮点数截断数据,即用8bit 表示指数,7bit 表示小数. FP16半精度浮点数,用5bit ...
- [转帖]Perf IPC以及CPU性能
https://plantegg.github.io/2021/05/16/Perf%20IPC%E4%BB%A5%E5%8F%8ACPU%E5%88%A9%E7%94%A8%E7%8E%87/ Pe ...
- 学习下Redis内存模型
作者:京东零售 吴佳 前言 redis,对于一个java开发工程师来讲,其实算不得什么复杂新奇的技术,但可能也很少人去深入了解学习它的底层的一些东西.下面将通过对内存统计.内存划分.存储细节.对象类型 ...
- Promise的异常穿透和中断Promise的链式请求
1.Promise的异常穿透 1==>当你使用Promise的then,进行链式调用的时候,可以在最后指定失败的回调 2==>前面任何操作出现了异常,都会传递到最后失败的回调中进行处理: ...