管道的概念
管道是一种最基本的IPC(进程通信)机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端
3. 规定数据从管道的写端流入管道,从读端流出
管道的原理:管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现
管道的局限性:
1. 数据自己读不能自己写
2. 数据一旦被读走,便不在管道中存在,不可反复读取
3. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动
4. 只能在有公共祖先的进程间使用管道。
头文件
#include <unistd.h>
函数原型
int pipe(int pipefd[2]);
调用成功返回0,失败返回-1并设置errno
Description
函数调用成功返回r/w两个文件描述符。无需open, 但需要手动close。
规定fd[0]-->r, fd[1]-->w, 就像0 对应标准输入,1对应标准输出一样。
向管道文件读写数据其实就是在读写内核缓冲区。
管道的优劣
优点:简单,相比信号,套接字实现进程间通信,简单很多。
缺点:
1. 只能单向通信,双向通信需建立两个管道。
2. 只能用于父子、兄弟进程(有共同祖先)间通信。该问题后来使用FIFO命名管道解决。
总结:
①读管道:
1. 管道中有数据,read返回实际读到的字节数。
2. 管道中无数据:
(1) 管道写端被全部关闭,read返回0 (好像读到文件结尾)
(2) 写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu)
②写管道:
1. 管道读端全部被关闭,进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)
2. 管道读端没有全部关闭:
(1) 管道已满,write阻塞。
(2) 管道未满,write将数据写入,并返回实际写入的字节数。
DEMO父子进程间通过管道通信
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <cstring>
using namespace std;
int main(){
int fd[2];
if(pipe(fd) == -1){
perror("create pipe error");
}
pid_t pid = fork();
if(pid == -1){
perror("fork error!");
}
if(pid == 0){ // child process read pipe
close(fd[1]);
char buf[BUFSIZ];
int len = read(fd[0], buf, sizeof(buf));
cout << "child process read pipe" << endl;
cout << "data: " << buf << endl;
cout << "size: " << len << endl;
cout << "Finished reading" << endl;
close(fd[0]);
}else{ // parent process write pipe
close(fd[0]);
const char * str = "Hello, my friend!";
cout << "parent process write pipe" << endl;
cout << "data: " << str << endl;
cout << "size: " << strlen(str) << endl;
write(fd[1], str, strlen(str));
cout << "Finished writing" << endl;
close(fd[1]);
sleep(1);
}
return 0;
}
Comments