Linux 进程通信(无名管道)
无名管道
无名管道是半双工的,就是对于一个管道来讲,只能读,或者写。
无名管道只能在相关的,有共同祖先的进程间使用(即一般用户父子进程)。
一个fork或者execve调用创建的子进程继承了父进程的文件描述符。
打开和关闭管道 int pipe(int filedes[2]); 在你从一个管道中读出或者写入数据,这个管道必须存在。 如果成功建立了管道,则会打开两个文件描述符,并把他们的值保存在一个整数数组中。 第一个文件描述符用于读取数据,第二个文件描述符用于写入数据。
管道的两个文件描述符相当于管道的两端,一端只负责读数据,一端只负责写数据 如果出错返回-1,同时设置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[2] = { 0 }; int no = 0; int status; //create the conduit 创建一个管道 并且打开两个文件描述符 //管道中,第一个文件描述符只读,第二个文件描述符只写 no = pipe(fdarr); if (no == -1) { printf("pipe() is failed ! message :%s\n", strerror(errno)); return -1; } //创建父子进程 pid_t child = fork(); if (child == -1) { printf("system is game over !\n"); return -1; } //定义缓存字符串数组 char buf[100] = { 0 }; if (child == 0) { /* 管道和文件一样,文件read函数以O_RDONLY方式打开也会阻塞,但是文件数据在本地,读取非常快,感觉不到阻塞, 但是管道以O_RDONLY方式打开,会阻塞进程,read()函数会等待管道另一端写入数据,直到另一端关闭文件描述符 */ //关闭子进程中的写文件描述符--对于父子进程共享文件描述符,只在单个进程中关闭,只能将文件描述符引用减一, //因为父子进程中,文件描述符被引用了两次,所以需要在父子进程中分别关闭,才能使文件描述符引用次数减一 close(fdarr[1]); while (read(fdarr[0], buf, sizeof(buf)) > 0) { printf("%s", buf); //清空缓存区 memset(buf, 0, sizeof(buf)); } //关闭子进程中读文件描述符 close(fdarr[0]); } else { //关闭父进程中的读描述符 close(fdarr[0]); //将键盘输入数据写入到管道中 strcpy(buf,"fly on air!\n"); write(fdarr[1], buf, strlen(buf)); //关闭管道写文件描述符 close(fdarr[1]); //等待子进程结束 wait(&status); printf("child process is close ! message :%d\n", WEXITSTATUS(status)); } return 10; }