linux进程间通信之管道(无名管道pipe)实现全双工双向通信
管道是什么:
1. 管道只能用于具有亲缘关系的进程之间通信。
2.管道是一种单工或者说半双工的通信方式,传递信息的方向是固定的,只能由一端传递到另一端。
头文件及函数原型:
#include <unistd.h>
int pipe(int fd[2]);
当用pipe 创建管道后,两个文件描述符fd[0],fd[1]就可以使用了,其中fd[0]用于读取,fd[1]用于写入。调用管道pipe返回值0表示成功,返回值-1表示失败。
pipe函数创建管道后,接着fork出子进程,子进程继承父进程管道。
代码举例来看:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define MAX_DATA_LEN 256
- #define DELAY_TIME 1
- int main() {
- pid_t pid;
- char buf[MAX_DATA_LEN];
- const char *data="Pipe Test";
- int real_read,real_write;
- int pipe_fd[2];
- memset((void*)buf,0,sizeof(buf));
- if(pipe(pipe_fd)<0){
- perror("Pipe create error!\n");
- exit(1);
- }
- if ((pid=fork())<0) {
- perror("Fork error!\n");
- exit(1);
- } else if (pid==0) {
- close(pipe_fd[1]);
- sleep(DELAY_TIME*3);
- if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
- printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
- }
- close(pipe_fd[0]);
- exit(0);
- } else {
- close(pipe_fd[0]);
- sleep(DELAY_TIME);
- if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
- printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
- }
- close(pipe_fd[1]);
- waitpid(pid,NULL,0);
- exit(0);
- }
- }
运行输出:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.
上述代码只能从父进程向子进程传递,如何从子进程向父进程传递呢?我们看到父进程关闭了管道读取端“close(pipe_fd[0]);”,子进程关闭了管道写入端“close(pipe_fd[1]);”,如果取消关闭这两个端,是否能够实现子进程向父进程传递呢。
父进程先发送,子进程接收,然后子进程再发送,父进程再接收,实现全双工互相通信,期望运行结果如下:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.
Child write 9 bytes from pipe: 'Pipe Test'.
Parent receive 9 bytes from pipe: 'Pipe Test'.
修改代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define MAX_DATA_LEN 256
- #define DELAY_TIME 1
- int main() {
- pid_t pid;
- char buf[MAX_DATA_LEN];
- const char *data="Pipe Test";
- int real_read,real_write;
- int pipe_fd[2];
- memset((void*)buf,0,sizeof(buf));
- if(pipe(pipe_fd)<0){
- perror("Pipe create error!\n");
- exit(1);
- }
- if ((pid=fork())<0) {
- perror("Fork error!\n");
- exit(1);
- } else if (pid==0) {
- //close(pipe_fd[1]);
- sleep(DELAY_TIME*3);
- if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
- printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
- }
- if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
- printf("Child write %d bytes into pipe: '%s'.\n",real_write,data);
- }
- close(pipe_fd[0]);
- exit(0);
- } else {
- //close(pipe_fd[0]);
- sleep(DELAY_TIME);
- if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
- printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
- }
- if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
- printf("Parent receive %d bytes from pipe: '%s'.\n",real_read,buf);
- }
- close(pipe_fd[1]);
- waitpid(pid,NULL,0);
- exit(0);
- }
- }
但是实际运行如下:
Parent write 9 bytes into pipe: 'Pipe Test'.
Parent receive 9 bytes from pipe: 'Pipe Test'.
可以看到,父进程发送的数据被父进程自己接收了,子进程读不到数据被阻塞了。显然这种方法不行。
因为管道是单工的,只能固定从一个方向传递到另一个方向。
要实现互相通信,一个管道是不行的,可以创建两个管道,一个管道是父写子读,另一个是子写父读。
代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <unistd.h>
- #define MAX_DATA_LEN 256
- #define DELAY_TIME 1
- int main() {
- pid_t pid;
- char buf[MAX_DATA_LEN];
- const char *data="Pipe Test";
- int real_read,real_write;
- int pipe_fd[2],pipe_fd2[2];
- memset((void*)buf,0,sizeof(buf));
- if(pipe(pipe_fd)<0){
- perror("Pipe create error!\n");
- exit(1);
- }
- if(pipe(pipe_fd2)<0){
- perror("Pipe create error!\n");
- exit(1);
- }
- if ((pid=fork())<0) {
- perror("Fork error!\n");
- exit(1);
- } else if (pid==0) {
- close(pipe_fd[1]);
- close(pipe_fd2[0]);
- sleep(DELAY_TIME*3);
- if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
- printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
- }
- if ((real_write=write(pipe_fd2[1],data,strlen(data)))>0) {
- printf("Child write %d bytes into pipe: '%s'.\n",real_write,data);
- }
- close(pipe_fd[0]);
- close(pipe_fd2[1]);
- exit(0);
- } else {
- close(pipe_fd[0]);
- close(pipe_fd2[1]);
- sleep(DELAY_TIME);
- if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
- printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
- }
- if ((real_read=read(pipe_fd2[0],buf,MAX_DATA_LEN))>0) {
- printf("Parent receive %d bytes from pipe: '%s'.\n",real_read,buf);
- }
- close(pipe_fd[1]);
- close(pipe_fd2[0]);
- waitpid(pid,NULL,0);
- exit(0);
- }
- }
运行结果:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.
Child write 9 bytes into pipe: 'Pipe Test'.
Parent receive 9 bytes from pipe: 'Pipe Test'.
可以看到,创建了两个管道 “int pipe_fd[2],pipe_fd2[2];”,
pipe_fd 是父写子读,pipe_fd2是子写父读,通过两个管道,实现了进程的全双工互相通信。