linux C 语言开发 (九) 进程间通讯--管道
文章的目的为了记录使用C语言进行linux 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
linux C 语言开发 (一) Window下用gcc编译和gdb调试
linux C 语言开发 (二) VsCode远程开发 linux
linux C 语言开发 (三) 建立云服务器
linux C 语言开发 (四) linux系统常用命令
linux C 语言开发 (五) linux系统目录结构
linux C 语言开发 (六) 程序的编辑和编译(vim、gcc)
linux C 语言开发 (七) 文件 IO 和标准 IO
linux C 语言开发 (八) 进程基础
linux C 语言开发 (九) 进程间通讯--管道
linux C 语言开发 (十) 进程间通讯--信号
Linux C到Android App开发推荐链接(入门十二章):
开源 java android app 开发(一)开发环境的搭建_csdn 开源 java android app-CSDN博客
开源 java android app 开发(一)开发环境的搭建-CSDN博客
开源 java android app 开发(二)工程文件结构-CSDN博客
开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客
开源 java android app 开发(四)GUI界面重要组件-CSDN博客
开源 java android app 开发(五)文件和数据库存储-CSDN博客
开源 java android app 开发(六)多媒体使用-CSDN博客
开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客
开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客
开源 java android app 开发(九)后台之线程和服务-CSDN博客
开源 java android app 开发(十)广播机制-CSDN博客
开源 java android app 开发(十一)调试、发布-CSDN博客
开源 java android app 开发(十二)封库.aar-CSDN博客
linux C到.net mvc开发推荐链接:
开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客
开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客
开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客
开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客
开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客、
内容:讲述进程间的IPC通讯,匿名管道和有名管道。IPC通讯对比文件读写,最简单的理解就是
目录:
1.IPC通讯
2.匿名管道
3.有名管道
一、IPC通讯--管道
Linux 提供了多种专门为 IPC 设计的机制,它们主要在内存中进行操作,速度极快,并提供了良好的同步和互斥机制。主要可以分为以下几类:
1. 基于通信的 IPC (用于交换数据)
这类机制关注于进程间的数据流动。
管道 (Pipe): 最基本的 IPC。分为匿名管道(用于有亲缘关系的进程,如父子进程)和命名管道 (FIFO)(用于无亲缘关系的进程)。数据是单向流动的字节流。
消息队列 (Message Queue): 消息的链表,存放在内核中。进程可以向队列中添加消息或读取消息。每个消息是一个数据块,有特定的类型,比管道更有结构。
信号 (Signal): 一种异步通知机制,用于通知进程某个事件已经发生(如 Ctrl+C 发送 SIGINT)。它携带的信息量很小(只有一个信号编号),主要用于控制,而非数据传输。
套接字 (Socket): 功能最强大、最通用的 IPC 机制,不仅可以用于同一台主机的进程间通信(Unix Domain Socket),还可以用于网络上的不同主机间的通信。TCP/IP socket 就是最著名的例子。
二、匿名管道
无名管道是最古老的进程通信方式, 有如下两个特点:
1. 只能用于有关联的进程间数据交互, 如父子进程, 兄弟进程, 子孙进程, 在目录中看不到文件节点, 读写文件描述符存在一个 int 型数组中。
2. 只能单向传输数据, 即管道创建好后, 一个进程只能进行读操作, 另一个进程只能进行写操作,读出来字节顺序和写入的顺序一样。
函数 | int pipe(int pipefd[2]) |
头文件 | #include <unistd.h> |
参数 pipefd[2] | 一个 int 型数组, 表示管道的文件描述符, pipefd[0]为读, pipefd[1]为写, 如下图所示: |
返回值 | 成功返回 0, 失败返回-1 |
功能 | 创建无名管道 |
无名管道使用步骤:
1. 调用 pipe()创建无名管道;
2. fork()创建子进程, 一个进程读, 使用 read(), 一个进程写, 使用 write()。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(void)
{
char buf[32] = {0};
pid_t pid;
// 定义一个变量来保存文件描述符
// 因为一个读端, 一个写端, 所以数量为 2 个
int fd[2];
// 创建无名管道
pipe(fd);
printf("fd[0] is %d\n", fd[0]);
printf("fd[2] is %d\n", fd[1]);
// 创建进程
pid = fork();
if (pid < 0)
{
printf("error\n");
} i
f (pid > 0)
{
int status;
close(fd[0]);
write(fd[1], "hello", 5);
close(fd[1]);
wait(&status);
exit(0);
} i
f (pid == 0)
{
close(fd[1]);
read(fd[0], buf, 32);
printf("buf is %s\n", buf);
close(fd[0]);
exit(0);
}
return 0;
}
演示效果
三、有名管道
有名管道中可以很好地解决在无关进程间数据交换的要求, 并且由于它们是存在于文件系统中的, 这也提供了一种比匿名管道更持久稳定的通信办法。 有名管道在一些专业书籍中叫做命名管道, 它的特点是1.可以使无关联的进程通过 fifo 文件描述符进行数据传递; 2.单向传输有一个写入端和一个读出端, 操作方式和无名管道相同。
函数详解如下所示:
函数 | int mkfifo(const char *pathname, mode_t mode) |
头文件 | #include <sys/types.h> #include <sys/stat.h> |
参数 pathname | 有名管道的路径和名称 |
参数 mode | 权限 |
返回值 | 成功返回 0, 失败返回-1 |
有名管道使用步骤:
1. 使用 mkfifo()创建 fifo 文件描述符。
2. 打开管道文件描述符。
3. 通过读写文件描述符进行单向数据传输。
具体代码:
创建两个无关联的进程, 一个进程创建有名管道并写数据, 另一个进程通过管道读数据。输入以下命令创建管道文件, 并查看, 如下图所示:
mkfifo fifo
ls ls -al
fifo_write.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{int ret;char buf[32] = {0};int fd;if (argc < 2){printf("Usage:%s <fifo name> \n", argv[0]);return -1;} if (access(argv[1], F_OK) == 1){ret = mkfifo(argv[1], 0666);if (ret == -1){printf("mkfifo is error \n");return -2;} printf("mkfifo is ok \n");}fd = open(argv[1], O_WRONLY);while (1){sleep(1);write(fd, "hello", 5);} close(fd);return 0;
}
fi fo_read.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char *argv[])
{char buf[32] = {0};int fd;if (argc < 2){printf("Usage:%s <fifo name> \n", argv[0]);return -1;} fd = open(argv[1], O_RDONLY);while (1){sleep(1);read(fd, buf, 32);printf("buf is %s\n", buf);memset(buf, 0, sizeof(buf));} close(fd);return 0;
}
编译和演示效果
注意需要先mkfifo fifo,再便宜 fifo_read.c,fifo_write.c