进程间通信(IPC)
进程间通信常用的4种方法
1. 管道:简单
2. 信号:系统开销小
3. 共享映射区:有无血缘关系的进程间通信都可以
4. 本地套接字:稳定
管道
匿名管道pipe
适用于有血缘关系的进程间通信
pipe函数
#include<unistd.h>
int pipe(int filedes[2]);
返回值:成功,返回0,否则返回-1。参数数组包含pipe使用的两个文件的描述符。fd[0]:读管道,fd[1]:写管道。
必须在fork()中调用pipe(),否则子进程不会继承文件描述符。两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
通过父子进程间通信,实现 ps aux | grep "bash"
#include <stdio.h> #include <unistd.h> int main() { int fd[2]; int ret = pipe(fd); if(ret == -1) { printf("pipe error"); exit(1); } printf("pipe[0] = %d\npipe[1] = %d\n", fd[0], fd[1]); pid_t pid = fork(); if(pid == -1) { perror("fork error"); exit(1); } //父进程执行 ps aux if(pid) { //写管道操作,关闭读端 close(fd[0]); //把标准输出重定向到管道写端 dup2(fd[1], STDOUT_FILENO); execlp("ps","ps", "aux", NULL); } //子进程执行 grep "bash" else if(pid == 0) { //关闭写端 close(fd[1]); //把管道读端重定向到标准输入 dup2(fd[0], STDIN_FILENO); execlp("grep", "grep", "bash", NULL); } close(fd[0]); close(fd[1]); return 0; }
通过兄弟进程间通信,实现 ps aux | grep "bash"
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main() { int fd[2]; int ret = pipe(fd); if(ret == -1) { printf("pipe error"); exit(1); } printf("pipe[0] = %d\npipe[1] = %d\n", fd[0], fd[1]); int i = 0; for(; i<2; i++) { pid_t pid = fork(); printf("pid = %d\n", pid); if(pid == -1) { perror("fork error"); exit(1); } else if(pid == 0) { break; } } //子进程1执行 ps aux if(i == 0) { //写管道操作,关闭读端 close(fd[0]); //把标准输出重定向到管道写端 dup2(fd[1], STDOUT_FILENO); execlp("ps","ps", "aux", NULL); } //子进程2执行 grep "bash" else if(i == 1) { //关闭写端 close(fd[1]); //把管道读端重定向到标准输入 dup2(fd[0], STDIN_FILENO); execlp("grep", "grep", "bash", NULL); } //父进程 else if(i == 2) { close(fd[0]); close(fd[1]); pid_t wpid; while((wpid = waitpid(-1, NULL, WNOHANG)) != -1) { if(wpid == 0) { continue; } printf("child process %d died\n", wpid); } } close(fd[0]); close(fd[1]); return 0; }
有名管道fifo实现无血缘关系进程间通信
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <fcntl.h> int main(int argc, const char* argv[]) { if(argc < 2) { printf("./a.out fifoname\n"); exit(1); } //判断文件是否存在 int ret = access(argv[1], F_OK); if(ret == -1) { int r = mkfifo(argv[1], 0664); if(r == -1) { perror("mkfifo error"); exit(1); } printf("fifo %s build success!", argv[1]); } int fd = open(argv[1], O_WRONLY); if(fd == -1) { perror("open error"); exit(1); } char *p = "hello world"; while(1) { sleep(1); int len = write(fd, p, strlen(p) + 1); } close(fd); return 0; }
#include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <fcntl.h> int main(int argc, const char* argv[]) { if(argc < 2) { printf("./a.out fifoname\n"); exit(1); } //判断文件是否存在 int ret = access(argv[1], F_OK); if(ret == -1) { int r = mkfifo(argv[1], 0664); if(r == -1) { perror("mkfifo error"); exit(1); } printf("fifo %s build success!", argv[1]); } int fd = open(argv[1], O_RDONLY); if(fd == -1) { perror("open error"); exit(1); } char buf[512]; while(1) { int len = read(fd, buf, sizeof(buf)); buf[len] = 0; printf("buf = %s\n, len = %d", buf, len); } close(fd); return 0; }