无名管道
无名管道是半双工的,就是对于一个管道来讲,只能读,或者写。
无名管道只能在相关的,有共同祖先的进程间使用(即一般用户父子进程)。
一个fork或者execve调用创建的子进程继承了父进程的文件描述符。
打开和关闭管道
int pipe(int filedes[]);
在你从一个管道中读出或者写入数据,这个管道必须存在。
如果成功建立了管道,则会打开两个文件描述符,并把他们的值保存在一个整数数组中。
第一个文件描述符用于读取数据,第二个文件描述符用于写入数据。
管道的两个文件描述符相当于管道的两端,一端只负责读数据,一端只负责写数据
如果出错返回-,同时设置errno
关闭一个文件描述符用close()函数
关闭一个管道的所有文件描述符等于关闭这个管道(不能读不能写)
pipe()函数打开管道一般不会失败
读写管道
读写管道与读写普通文件方式一样,调用write与read函数即可。
几乎不会在一个进程中打开一个管道仅供进程自己使用,管道是用来交换数据的。
因为一个进程已经能够访问它要通过管道共享的数据,和自己共享数据是没有意义的。
试图对一个管道的某一端同时进行读写操作是一个严重的错误。
//无名管道
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int arg, char * args[])
{
//定义文件描述符数组
int fdarr[] = { };
int no = ;
int status;
//create the conduit 创建一个管道 并且打开两个文件描述符
//管道中,第一个文件描述符只读,第二个文件描述符只写
no = pipe(fdarr);
if (no == -)
{
printf("pipe() is failed ! message :%s\n", strerror(errno));
return -;
}
//创建父子进程
pid_t child = fork();
if (child == -)
{
printf("system is game over !\n");
return -;
}
//定义缓存字符串数组
char buf[] = { };
if (child == )
{
/*
管道和文件一样,文件read函数以O_RDONLY方式打开也会阻塞,但是文件数据在本地,读取非常快,感觉不到阻塞,
但是管道以O_RDONLY方式打开,会阻塞进程,read()函数会等待管道另一端写入数据,直到另一端关闭文件描述符
*/
//关闭子进程中的写文件描述符--对于父子进程共享文件描述符,只在单个进程中关闭,只能将文件描述符引用减一,
//因为父子进程中,文件描述符被引用了两次,所以需要在父子进程中分别关闭,才能使文件描述符引用次数减一
close(fdarr[]);
while (read(fdarr[], buf, sizeof(buf)) > )
{
printf("%s", buf);
//清空缓存区
memset(buf, , sizeof(buf));
}
//关闭子进程中读文件描述符
close(fdarr[]);
} else
{
//关闭父进程中的读描述符
close(fdarr[]);
//将键盘输入数据写入到管道中
strcpy(buf,"fly on air!\n");
write(fdarr[], buf, strlen(buf));
//关闭管道写文件描述符
close(fdarr[]);
//等待子进程结束
wait(&status);
printf("child process is close ! message :%d\n", WEXITSTATUS(status));
}
return ;
}
![Linux 进程通信(无名管道) Linux 进程通信(无名管道)](/default/index/img?u=aHR0cHM6Ly9iYnNtYXguaWthZmFuLmNvbS9zdGF0aWMvTDNCeWIzaDVMMmgwZEhCekwybHRZV2RsY3pJd01UVXVZMjVpYkc5bmN5NWpiMjB2WW14dlp5ODJORFEzTkRNdk1qQXhOakE1THpZME5EYzBNeTB5TURFMk1Ea3dNVEUwTkRBd09EWTVPUzB4TnpVNE9EQXhNelV4TG5CdVp3PT0uanBn)