管道:从一个进程连接到另一个进程的数据量
无名管道:pipe
特点:
(1)用于具有血缘关系的进程间通信
(2)是一个只能单向通信的通信信道
(3)面向字节流
(4)自带同步机制,原子性写入
(5)管道也是文件,但它的生命周期是随进程的
相关函数:创建pipe:int pipe(int pipefd[2]);
参数:pipefd:是一个输出型参数,文件描述符数组,pipefd[0]表示读端,pipefd[1]表示写端
返回值:创建成功返回0,创建失败返回-1/错误代码
创建pipe:
#include<stdio.h>
#include<unistd.h>
// pipe
int main(){
int pipefd[2]={0};
if(pipe(pipefd) != 0)
{
perror("pipe error");
return 1;
}
printf("pipefd[0] = %d\n",pipefd[0]);
printf("pipefd[1] = %d\n",pipefd[1]);
return 0;
}
运行结果:
原因是pipefd[0]和pipedfd[1]都是文件描述符,0、1、2已被占用
pipe大小:64kb
通过计数器发现写入了65536个字符,65536个字符,即64kb便不再写入
父进程读,子进程写的代码实现:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
// pipe
int main(){
int pipefd[2]={0};
if(pipe(pipefd) != 0)
{
perror("pipe error");
return 1;
}
printf("pipefd[0] = %d\n",pipefd[0]);
printf("pipefd[1] = %d\n",pipefd[1]);
// 实现父进程读取,子进程写入
if(fork() == 0){
// child
close(pipefd[0]);
const char *msg = "hello father\n";
int count = 0;
char c = 'a';
while(1){
write(pipefd[1],msg,strlen(msg));
sleep(1);
}
exit(0);
}
// father
close(pipefd[1]);
// 读
while(1){
char buffer[64] = {0};
ssize_t s = read(pipefd[0],buffer,sizeof(buffer)-1);// 如果read的返回值=0,意味着子进程关闭
if(s>0){
buffer[s] = 0;
printf("父进程收到了:%s\n",buffer);
// 父进程没有sleep
}else if(s == 0)
{
printf("child quit\n");
break;
}else{
perror("read error");
break;
}
}
return 0;
}
管道读写的四种情况:
读端读得慢或不读,写端等读端
读端关闭,写端收到SIGPIPE信号关闭
写端写得慢或不写,读端等写端
写端关闭,读端会读完pipe内部的数据后读到0,表明读到文件结尾