(一)管道的创建
管道是一种最基本的IPC机制,由pipe函数创建:
#include <unistd.h>
int pipe ( int filedes[2] );
pipe函数需要一个形参(一个含有2个整型元素的数组),创建成功返回0,失败返回-1
该函数本质原理:
当父进程创建子进程,子进程则按照父进程的PCB进行部分拷贝形成自己的PCB。在父进程的PCB中含有一个叫做files_struct的结构,而这个结构中主要内容就是包含了该进程打开的所有文件的地址,即一个指针数组(默认情况下打开三个文件,标准输入,标准输出,标准错误,分别对应指针数组下标为0, 1, 2的元素,下标即是文件描述符)。当父进程调用pipe函数,则会在内核中开辟一块缓冲区用于通信,并且它含有一个读端一个写端,则在files_struct中多了两个元素对应着打开的文件地址在files_struct中的该管道的读端和写端,当父进程创建子进程,则files_struct也被拷贝一份到子进程的PCB,那么父子进程就看到了一份公共资源
打开的文件地址在files_struct中的规则:
改地址存放在files_struct指针数组中未使用的最小的元素中
(二)代码实现
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int array[2] = {0};
int key = pipe(array);
if(key < 0){
perror("pipe");
return -1;
}
pid_t ret = fork();
if(ret < 0){
// shi bai
perror("fork");
return -2;
}else if(ret == 0){
//child -> read
close(array[1]);
int count = 5;
char buf[128];
while(count--)
{
ssize_t _s = read(array[0], buf, sizeof(buf)-1);
if(_s < 0){
perror("write");
return -4;
}else{
buf[_s] = '\0';
printf("%s\n",buf);
}
}
close(array[0]);
}
else{
//father -> write
//
char buf[128]= "hello bit";
int count = 5;
close(array[0]);
while(count--)
{
ssize_t _s = write(array[1], buf, sizeof(buf)-1);
if(_s < 0){
perror("write");
return -4;
}
sleep(1);
}
close(array[1]);
}
return 0;
}
(三)总结
匿名管道必须依赖于父子关系的一种父子进程间的通信方式,其原理本质是借助父进程创建子进程而子进程的PCB继承父进程的大部分信息包括files_struct结构,则父子进程则可以看到同一份打开的文件!