本系列文章主要是学习记录Linux下进程间通信的方式。
常用的进程间通信方式:管道、FIFO、消息队列、信号量以及共享存储。
参考文档:《UNIX环境高级编程(第三版)》
参考视频:Linux进程通信 推荐看看,老师讲得很不错
Linux核心版本:2.6.32-431.el6.x86_64
注:本文档只是简单介绍IPC,更详细的内容请查看参考文档和相应视频。
本文介绍利用管道进行进程间的通信。
管道是最古老的一种方式,局限性:
1 #include <unistd.h> 2 int pipe(int pipefd[2]); 3 说明:常见一个pipe 4 返回值:成功返回0,出错返回-1 5 参数[out]:fd保存返回的两个文件描述符,fd[0]为读而打开,fd[1]为写而打开。fd[1]的输出是fd[0]的输入。
通信模型一:进程先调用pipe,接着调用fork,从而创建从父进程到子进程的IPC通道。
通信模型二:从父进程到子进程的通道。父进程关闭管道的读端(fd[0]),子进程关闭写端(fd[1])。
当管道一端被关闭后,以下两条规则起作用:
当读(read)一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,表示文件结束。
如果写(write)一个读端已被关闭的管道,则产生信号SIGPIPE。
(1)案例1
创建一个从父进程到子进程的管道,并且父进程通过该管道向子进程传送数据。
1 #include <stdio.h> 2 #include <unistd.h> 3 4 #define MAXLINE 512 5 6 int main(void) 7 { 8 int n; 9 int fd[2]; 10 pid_t pid; 11 char line[MAXLINE]; 12 13 if (pipe(fd) < 0) { //创建管道 14 perror("pipe error!"); 15 return -1; 16 } 17 if ((pid = fork()) < 0) { //创建子进程 18 perror("fork error!"); 19 return -1; 20 } else if (pid > 0) { //父进程 21 close(fd[0]); //父进程关闭读管道 22 write(fd[1], "hello world\n", 12); //父进程向管道中写入数据 23 close(fd[1]); 24 wait(0); //等待子进程结束 25 } else { //子进程 26 close(fd[1]); //子进程关闭写管道 27 n = read(fd[0], line, MAXLINE); //子进程从管道中读取数据 28 write(STDOUT_FILENO, line, n); //标准输出 29 close(fd[0]); 30 } 31 32 return 0; 33 }
(2)案例2
使用pipe实现类似于:cat /etc/passwd | grep root这个命令。
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 5 char *cmd1[3] = {"/bin/cat", "/etc/passwd", NULL}; 6 char *cmd2[3] = {"/bin/grep", "root", NULL}; 7 8 int main(void) 9 { 10 int fd[2]; 11 int i = 0; 12 pid_t pid; 13 14 if (pipe(fd) < 0) { 15 perror("pipe error"); 16 exit(1); 17 } 18 19 for (i = 0; i < 2; i++) { 20 pid = fork(); 21 if (pid < 0) { 22 perror("fork error"); 23 exit(1); 24 } else if (pid == 0) { 25 if (i == 0) { //第一个子进程 26 //负责往管道写入数据 27 close(fd[0]); //关闭读端 28 //cat命令执行结果是标准输出,需要将标准输出重定向到管道写端 29 //下面命令执行的结果会写入到管道中,而不是输出到屏幕 30 if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { 31 perror("dup2 error"); 32 exit(1); 33 } 34 close(fd[1]); //已经复制了一份,原来的可以关闭 35 //调用exce函数执行cat命令 36 if (execvp(cmd1[0], cmd1) < 0) { 37 perror("execvp error"); 38 exit(1); 39 } 40 break; 41 } 42 if (i == 1) { //第二个子进程 43 //负责从管道读取数据 44 close(fd[1]); //关闭写端 45 //grep命令默认读取的内容来源于标准输入 46 //需要将标准输入重定向到管道的读端 47 //下面命令执行时从管道的读端读取内容,而不是从标准输入读取 48 if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) { 49 perror("dup2 error"); 50 exit(1); 51 } 52 close(fd[0]); 53 //调用exce函数执行grep命令 54 if (execvp(cmd2[0], cmd2) < 0) { 55 perror("execvp error"); 56 exit(1); 57 } 58 break; 59 } 60 } else { //父进程,仅用于创建子进程 61 //等待子进程创建并回收 62 if (i == 1) { 63 //等待子进程全部创建完毕,才回收 64 close(fd[0]); 65 close(fd[1]); 66 wait(0); 67 wait(0); 68 } 69 } 70 } 71 72 return 0; 73 }
原文:https://www.cnblogs.com/mrlayfolk/p/13027545.html