五、进程间通信-无名管道
1、无名管道
用于具有亲缘关系的进程间通信(常见的就是父子进程),数据只能单向流动。
(1)创建管道
#include<unistd.h>
int pipe(int pipefd[2]);
参数:
- pipefd[2]:参数为两个文件描述符,一个读文件描述符,一个写文件描述符。
返回值:
- 成功返回0
- 失败返回-1,且errno错误码被设置。
(2)特点:
-
特殊文件(没有名字),无法使用open,但是可以使用close.
-
只能通过子进程继承文件描述符的形式来使用。
-
write和read操作可能会zuse进程。
-
所有文件描述符被关闭之后,无名管道被销毁。
(3)使用步骤
-
父进程pipe无名管道
-
fork子进程。
-
close无用端口。
-
write/read读写端口。
-
close读写端口。
(4)应用实例
#include<unistd.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAX_DATA_LEN 256 #define DELAY_TIME 1 /******父进程通过管道传输数据到子进程**********/ int main() { pid_t pid; int pipe_fd[2]; char buf[MAX_DATA_LEN]; const char data[] = "Pipe Test Program"; int real_read,real_write; memset((void*)buf,0,sizeof(buf)); /*创建管道*/ if(pipe(pipe_fd) < 0) { printf("pipe create error!\n"); exit(1); } /*创建子进程*/ if((pid=fork()) == 0) { /*子进程关闭写文件描述符,并通过使子进程暂停3s等待父进程已关闭相应的读描述符*/ close(pipe_fd[1]); sleep(DELAY_TIME*3); /*子进程读取管道内容*/ if((real_read = read(pipe_fd[0],buf,MAX_DATA_LEN)) > 0) { printf("%d bytes read from the pipe is '%s'\n",real_read,buf); } /*关闭子进程读描述符*/ close(pipe_fd[0]); exit(0); } else if(pid > 0) { /*关闭父进程读描述符,并通过使父进程暂停1s等待子进程已关闭相应的写描述符*/ close(pipe_fd[0]); sleep(DELAY_TIME); if((real_write == write(pipe_fd[1],data,strlen(data)))!= -1) { printf("Parent write %d bytes:'%s'\n",real_write,data);; } /*关闭父进程写描述符*/ close(pipe_fd[1]); /*收集子进程退出信息*/ waitpid(pid,NULL,0); exit(0); } return 0; }
-
定义一个数组pipe_fd,在创建匿名管道后通过数组返回管道的文件描述符。
-
调用pipe()创建一个匿名管道,创建成功则得到两个文件描述符pipe_fd[0]、 pipe_fd[1],否则返回-1。
-
调用fork()创建一个子进程,如果返回值是0则表示此时运行的是子进程,那么在子进程中调用close()函数关闭写描述符,并使子进程睡眠3s等待父进程已关闭相应的读描述符。
-
子进程调用read()函数读取管道内容,如果管道没有数据则子进程将被阻塞,读取到数据就将数据打印出来。特别地如果调用read()函数读取一个关闭了写描述符的管道,那么read()会返回0,(本例子中父进程的写描述符没有关闭)。
-
调用close()函数关闭子进程读描述符。
-
如果fork()函数的返回值大于0,则表示此时运行的是父进程,那么在父进程中先调用close()关闭管道的读描述符,并且等待1s,因为此时可能子进程先于父进程运行,暂且.等待一会。
-
父进程调用write()函数将数据写入管道。
-
关闭父进程写描述符。
-
调用waitpid()函数收集子进程退出信息并退出进程。