1:管道
管道是比较古老的进程间的通信方式。主要有有名管道和无名管道两种。2:无名管道
它的特点就是: 1:只能使用在具有亲缘关系的进程之间的通信(父子进程或者兄弟进程之间)。因为只有具有亲缘关系的进程才能继承其创建的文件描述符。 2:是一个半双工的通信模式,具有固定的读端和写段。 3:可以将管道看着特殊的文件,也可以调用read()和write()操作。管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1],其中fd[0]是固定用于读管道, 而fd[1]是固定用于写管道,构成一个半双工通道。 当一个管道共享多对文件描述符时,若将其中的一对读写文件描述符都删除,则该管道将失效。
上面插图来自《linux应用程序开发标准教程》中,从图中可以看到当fork()后 , 子进程会继承父进程创建的管道,这样父子进程都拥有了自己的读写通道, 从而实现了父子之间的读写,只需要把无关的读端或写段的文件描述符关闭即可。 例如上图中,父进程负责读段,则把它的写段fd[1]关闭, 子进程负责写,则把它的读段fd[0]关掉。这样就建立起来一条“子进程写父进程读”的通道。 下面来看一下无名管道的实例,直接上代码: #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #define MAX_DATA_LEN 128 #define DELAY_TIME 1 int main() { pid_t pid; int pipe_fd[2]; char buf[MAX_DATA_LEN] = {0}; const char data[] ="Pipe Test Program"; int real_read, real_write; if( pipe(pipe_fd) < 0) { printf("Pipe create error\n"); exit(1); } if((pid = fork()) == 0) { /* clode write fd */ close(pipe_fd[1]); sleep(DELAY_TIME *3); if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0) { printf("Read data from pipe is %s\n", buf); } close(pipe_fd[0]); exit(0); } else if (pid > 0) { /*close read fd*/ close(pipe_fd[0]); sleep(DELAY_TIME); if ((real_write = write(pipe_fd[1], data, strlen(data))) != -1) { printf("Write to pipe is: %s\n", data); } { /* clode write fd */ close(pipe_fd[1]); sleep(DELAY_TIME *3); if ((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) > 0) { printf("Read data from pipe is %s\n", buf); } close(pipe_fd[0]); exit(0); } else if (pid > 0) { /*close read fd*/ close(pipe_fd[0]); sleep(DELAY_TIME); if ((real_write = write(pipe_fd[1], data, strlen(data))) != -1) { printf("Write to pipe is: %s\n", data); } close(pipe_fd[1]); waitpid(pid, NULL, 0); exit(0); } return 0; } 运行结果: Write to pipe is: Pipe Test Program Read data from pipe is Pipe Test Program3:有名管道
有名管道突破了无名管道的限制,可以使两个不相关的进程实现彼此之间的通信。相当于创建一个文件,建立管道之后,两个进程可以把它当做普通文件一样进行读写操作。严格遵循先进先出规则,对管道及FIFO的读写总是从开始出返回数据,对它们的写则把数据添加到末尾,需要指出的是不支持lseek()等文件定位操作。 可以采用mkdfifo()函数来创建一个命名管道,创建成功后就可以使用open, read, write函数进行操作。 mkfifo函数原型: int mkfifo(const char *filename, mode_t mode) 传参: filename为要创建的管道,包括路径名 mode只创建的管道权限,一般有O_RDONLY(读管道), O_WRONLY(写管道),O_RDWR(读写管道),O_NONBLOCK:非堵塞管道。 O_CREAT(如果文件不存在,则新建文件),O_EXCL:可以测试文件是否存在。 下面来看一个有名管道的例子,为了方便看代码,直接将命名管道应用在父子进程间通信: 这#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define MYFIFO "myfifo" #define MAX_DATA_LEN 128 #define DELAY_TIME 1 int main() { pid_t pid; int pipe_fd[2]; char buf[MAX_DATA_LEN] = {0}; const char data[] ="Pipe Test Program"; int real_read, real_write; int fd = 0; // memset((void *)buf, 0, sizeof(buf)); if(access(MYFIFO, F_OK) == -1) { if ((mkfifo(MYFIFO, 0666) < 0) ) printf("Can not create fifo file\n"); exit(1); } } if((pid = fork()) == 0) { /* open write fifo */ fd= open(MYFIFO,O_WRONLY); if ( fd == -1) { printf("Open write file error\n"); exit(1); } if(write(fd, data, strlen(data)) > 0) { printf("Write %s to FIFO\n", data); } close(fd); exit(0); } else if (pid > 0) { /*open write fifo */ fd = open(MYFIFO, O_RDONLY); if (fd == -1) { printf("Open fifo error\n"); exit(1); } if(read(fd, buf, MAX_DATA_LEN) > 0) { printf("Read %s from FIFO\n", buf); } close(fd); exit(0); } return 0; }运行结果: Write Pipe Test Program to FIFO Read Pipe Test Program from FIFO
下一节将温习信号的使用