以下内容是简摘自:https://blog.csdn.net/bit_clearoff/article/details/55105816
作者:_stark 原文章很棒。
一、管道的创建
#include<unistd.h>
pipe(int fd[2]);
它由输出型参数fd返回两个文件描述符,fd[0]为读而打开,fd[1]为写而打开,fd[1]的输出是fd[0]的输入,当管道创建成功后pipe函数返回0,如果创建失败则返回-1,fd[0]和fd[1]之间的关系如下图:
二、如何通过pipe进行通信
上面我们在单个进程中建立了管道,但是实际上,单个进程中的管道是没有什么用的,通常,进程会先调用pipe函数产生管道,接着调用fork()函数,fork函数会将父进程的相关数据结构继承到子进程中,这样就使子进程中的文件描述符表中的fd[0]和fd[1]指向父进程所指向的管道文件,这样就能实现两个进程之间的通信了。上面的过程如下图:
三、利用pipe通信的相关规则
对于一个从子进程到父进程的管道(子进程写,父进程读),父进程关闭fd[1],子进程关闭fd[0],当管道的一段被关闭后(在上面的基础上关闭管道的一端)下列规则起作用:
1、当读一个写端已经被关闭的管道时,
在所有的数据都被读取后,read返回0(read返回0表示已经读到文件结束符);
2、如果写一个读端已经被关闭的管道,
则会产生相关信号对写段的进程进行终止,如果忽略该信号或捕捉该信号并从处理程序返回,则write会返回-1,errno会设置为EPIPE;
3、如果管道的读端和写端都没有关闭,但是管道的写端没有再向管道写数据了。
这时如果管道中没有数据了,那么在此read进程会产生阻塞,直到管道中有数据了才读取数据并返回。
4、如果有指向管道读端的文件描述符没有关闭,而持有管道读端的没有从管道中读数据, 这时有进程向管道中写数据,如果管道被写满再向管道写数据是,再次write会导致进程阻塞,直到管道中有空间了才会继续向管道中写数据并返回。
四、测试代码雏形
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{
int fd[2]; //creat pipe
if(pipe(fd) != 0)
{
perror("pipe");
exit(1);
}
pid_t id = fork();
if(id == 0)
{
printf("Child\n");
sleep(2);
const char* msg = "Hello.\n";
close(fd[0]);
int count = 3;
while(count --)
{
printf("child is writing...\n");
ssize_t size = write(fd[1], msg, strlen(msg));
printf("size: %ld\n", size);
sleep(1);
}
close(fd[1]);
exit(0);
}
else
{
//father ---> read fd[0]
printf("Father\n");
sleep(2);
close(fd[1]);
char buf[1024];
int count = 3;
while(1)
{
printf("Father is reading...\n");
ssize_t len = read(fd[0], buf, 1024);
if(len > 0)
{
buf[len] = '\0';
printf("child say : %s", buf);
}
else if(len == 0)
{
printf("Read the end of pipe\n");
break;
}
else
{
perror("read");
exit(1);
}
}
close(fd[0]);
int status = 0;
pid_t _pid = waitpid(id, &status, 0);
if(_pid == id)
{
printf("Wait sucess for child\n");
printf("Exit code: %d, Exit signal: %d\n", (status>>8)&0xff, status&0xff);
}
else
perror("wait");
exit(0);
}
return 0;
}
运行结果: