开启辅助访问 切换到窄版

打印 上一主题 下一主题

Linux进程间通信方式(1)-管道(样例代码解读)

[复制链接]
作者:wyxc0124 
版块:
嵌入式操作系统 linux 发布时间:2020-12-11 14:56:55
9740
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言
对于一个大型的程序,划分子模块(比如 DDD,Domain Drived Design)是一种常见的手段,它能够做到代码灵活部署和解耦,比较典型的是控制模块和业务模块。但这也带来了一个问题:如何部署不同的子模块?你有以下几种选择:
1)单线程2)共进程多线程部署3)共 docker 跨进程部署4)跨 vm(虚拟机)部署对于跨 vm 的场景,进程间主要靠 socket 通信(创建套接字)。而对于同 vm 上跨进程独立部署的场景,必然绕不开到 IPC(进程间通信),进程间的通信方式有:管道、命名管道、消息队列、共享内存及信号量。而今天,我们先从管道开始,通过解读一个样例程序,来初步了解下管道要怎么用。
C 语言 fork 函数的用法
在介绍管道之前,我们先准备下基础知识:fork 函数。它的作用是在主进程里创建一个子进程,而这个 fork 函数调用非常奇妙:
它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:1)在父进程中,fork 返回新创建的子进程的进程 ID;2)在子进程中,fork 返回 0;3)如果出现错误,fork 返回一个负值;另外要知道的是,子进程是从 fork 函数后的指令开始执行的。
样例代码
#include #include #include #include #include int main{int _pipe = {0, 0};int ret = pipe(_pipe); // 创建管道,对应两个文件描述符,分别指向管道的两端if (ret == -1) {printf("create pipe error");return 1;}printf("_pipe is %d, _pipe is %d\n", _pipe, _pipe);pid_t id = fork; // 父进程fork子进程,子进程从fork后面的指令开始执行if (id < 0) {printf("fork error");return 2;} else if (id == 0) { // child, 写printf("child writing\n");close(_pipe);int count = 4;const char *msg = "i have a dream!";while (count--) {write(_pipe, msg, strlen(msg));printf("server# %s\n", msg);}close(_pipe);exit(1); // 终止正在执行的进程,异常退出} else { // father, 读printf("father reading\n");close(_pipe);char msg;clock_t t1;while (true) {ssize_t s = read(_pipe, msg, sizeof(msg) - 1);if (s > 0) {msg = '\0';printf("client# %s\n", msg);t1 = clock;} else {clock_t t2 = clock;double t = (double)(t2 - t1) / CLOCKS_PER_SEC;if (t > 3.0) { // 如果连续3秒没收到数据,则不再从管道读break;}}}if (waitpid(id, NULL, 0) != -1) { // 阻塞等待子进程结束printf("child process has exited\n");}}return 0;}上述代码中:
1)主进程创建了一个子进程,子进程负责向管道里写字符串。注意:写的时候要关闭读端,即 close(_pipe);
2)主进程负责从管道里读字符串。注意:读的时候要关闭写端,即 close(_pipe);
3)当主进程连续 3秒 从管道里读不到数据时,主进程退出读数据操作;
4)由于主进程和子进程是异步执行的,所以主进程在执行到函数 waitpid 处时,阻塞等待子进程结束;
5)主进程从管道读数据时,一次读完所有字符串。
程序运行结果

由于主进程和子进程异步执行的,程序运行结果不限于上图所示。
总结
管道作为 Linux 程序中一种最基本的 IPC 通信方式,显然局限性太大了。首先,它只适用于具有亲缘关系的进程间通信,比如父子进程、兄弟进程等。其次,它只能实现单向通信,如果要想实现双向通信,得定义另一个管道。相比之下,另一种 IPC 通信方式则灵活得多,那就是消息队列,写进程可以往消息队列里扔数据块,而数据块的类型可以是不一样的。关于消息队列的深度解析,且听下回分解。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表