Linux进程间通信——管道

管道

  • 什么是管道?一个进程连接到另一个进程的一个数据流称为一个“管道” 。
匿名管道pipe
  • 用于父子间的通信
  • 管道最大64K , 由环形队列组成
  • 需要占用两个文件描述符 , 分别作为管道读端、写端
  • 管道是半双工的 , 需要确定通信方向父写子读 , 关闭父读、子写子写父读 , 关闭子读、父写
  • 优点:稳定、经典
pipe函数原型头文件:
int pipe(int file_descriptor[2]);
功 能:创建一无名管道参 数:file_descriptor:文件描述符数组,其中file_descriptor[0]表示读端,file_descriptor[1]表示写端返回值:成功返回0 , 失败返回-1
开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信 。
Linux进程间通信——管道文章插图
1、父进程调用pipe开辟管道 , 得到两个文件描述符指向管道的两端 。 2、父进程调用fork创建子进程 , 那么子进程也有两个文件描述符指向同一管道 。 3、父进程关闭管道读端 , 子进程关闭管道写端 。 父进程可以往管道里写 , 子进程可以从4、管道里读 , 管道是用环形队列实现的 , 数据从写端流入从读端流出 , 这样就实现了进程间通信 。
#include #include #define MAXLINE 80int main(void){ int n; int fd[2]; pid_t pid; char line[MAXLINE]; if (pipe(fd) < 0){perror("pipe");exit(1); } if ((pid = fork()) < 0){perror("fork");exit(1); } if (pid > 0) // 父进程{close(fd[0]);//关闭读端write(fd[1], "hello world\n", 12);wait(NULL); } else//子进程 {close(fd[1]);//关闭写端n = read(fd[0], line, MAXLINE);write(STDOUT_FILENO, line, n); } return 0;}运行结果
Linux进程间通信——管道文章插图
注意事项
  • 如果试图从管道写端读取数据 , 或者向管道读端写入数据都将导致错误发生
  • 写端未写完 , 写端暂时无数据 , 读端再次去读 , read发生阻塞(读太快)
  • 读端未读完 , 写端满了 , 写端再次写 , write发生阻塞(写太快)
  • 读端关闭 , 写端写数据 , 产生SIGPIPE信号 , 默认会终止进程
  • 写端关闭 , 当数据读完 , 再次读返回0
Linuxc/c++服务器开发高阶视频 , 电子书学习资料后台私信【架构】获取
Linux进程间通信——管道文章插图
Linux进程间通信——管道文章插图
有名管道fifopipe是有血缘关系进程之间的通信 , 那么当没有血缘关系的进程想要通信怎么办?
  • 创建一个有名管道fifo(也叫做named pipe) , 解决无血缘关系的进程通信
  • fifo是一个设备文件 , 本身无大小 , 在文件系统中以文件名的形式存在 , 因此即使进程与创建fifo的进程不存在血缘关系也依然可以通信 , 前提是可以访问该路径 。
  • fifo总是遵循先进先出的原则 , 即第一个进来的数据会第一个被读走

Linux进程间通信——管道文章插图
与匿名管道pipe的区别
  • 提供了一个路径名与之关联 , 以fifo文件的形式存储于文件系统中 , 能够实现任何两个进程之间通信 。 而匿名管道对于文件系统是不可见的 , 它仅限于在父子进程之间的通信 。但是fifo底层是由pipe实现的 。
如何创建fifo?
  • 命令行上创建
  • 程序内创建头文件:#include #include 函数原型:int mkfifo(const char *pathname, mode_t mode);
做个测试 , 分别写两个程序 , 一个写 , 一个读写进程
#include #include #include #include #include #include #include int main(int argc, char* argv[]){ int fd; char buff[1024] = "hello world\n"; if (argc < 2) {printf("enter you fifoname\n");exit(1); } fd = open(argv[1], O_WRONLY);//只写方式打开 if (fd < 0) {perror("open\n"); } write(fd, buff, strlen(buff));//写入hello world close(fd); return 0;}读进程
#include #include #include #include #include #include #include int main(int argc, char* argv[]){ int fd; int len; char buff[1024] = "hello world\n"; if (argc < 2) {printf("enter you fifoname\n");exit(1); } fd = open(argv[1], O_RDONLY);//只写方式打开 if (fd < 0) {perror("open\n"); } len = read(fd, buff, sizeof(buff)); write(STDOUT_FILENO, buff, len); close(fd); return 0;}【Linux进程间通信——管道】测试结果如下
Linux进程间通信——管道文章插图
首先myfifo是我们提前创建好的fifo管道文件 , 然后执行写进程 , 再执行读进程 。 读到了hello world , 执行前后myfifo文件大小都为0