IPC通信概述
一、管道通信
管道是一种半双工的通信方式,具有固定的读端和写端,而且只支持有血缘关系的进程之间通信。因为管道是只存在于内存中,并不属于任何的系统文件。
头文件:#include <unistd.h>
函数原型:int pipe(int pipefd[2]);
函数参数:fd[0]代表读端,fd[1]代表写端
函数详解:一旦建立一个管道,就会创建并打开两个文件描述符,当fork出子进程后,也会复制两份相同的文件描述符,这样就可以实现父子进程间的通信。
例子:用pipe实现ps aux |grep bash的命令,并输出到屏幕上。
补充说明:grep是阻塞式的命令,会匹配到输入并输出到屏幕上。
1 #include <iostream> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <sys/wait.h> 5 6 using namespace std; 7 int main(int argc, char *argv[]) 8 { 9 int fd[2]; 10 if(pipe(fd) < 0) // 创建一个管道 11 { 12 cout << "open pipe error" << endl; 13 return -1; 14 } 15 pid_t pid = fork(); // 创建一个子进程 16 if(pid < 0) 17 { 18 cout << "create process failed" << endl; 19 } 20 if(pid == 0) 21 { 22 close(fd[0]); 23 dup2(fd[1], STDOUT_FILENO); // 将标准输出 重定向到 写端 24 execlp("ps", "ps", "aux", NULL); 25 } 26 else 27 { 28 close(fd[1]); 29 dup2(fd[0], STDIN_FILENO); // 将标准输入重定向到读端 30 execlp("grep", "grep", "bash", NULL); 31 wait(NULL); 32 } 33 34 return 0; 35 }
二、FIFO实现通信
FIFO,也称为命名管道,是一种文件类型。
FIFO也是一种管道,和pipe不同的是,FIFO是以一种特殊设备文件形式存在于文件系统中,支持没有血缘关系的进程间进行通信。
头文件:#include <sys/types.h>
#include <sys/stat.h>
函数原型:int mkfifo(const char *pathname, mode_t mode);
函数参数:mode参数和open函数中的mode相同
三、mmap通信
mmap是通过创建一个映射区来实现进程间通信,也就类似于操作同一块内存。
函数原型:
1 #include <sys/mman.h> 2 3 void *mmap(void *addr, size_t length, int prot, int flags, 4 int fd, off_t offset); 5 int munmap(void *addr, size_t length);//释放映射区
函数参数:
addr:传null
length:映射区的长度
prot:PROT_READ 可读 | PROT_WRITE可写
flag:MAP_SHARED 共享的,对内存的修改会影响到源文件
MAP_PRIVATE 私有的
fd:文件描述符,open打开一个文件,如果文件描述符先关闭,对mmap的映射区是没有影响的。
offset:偏移量,必须为4096的整数倍
返回值:成功返回可用的内存首地址,失败返回MAP_FAILED
利用mmap实现无血缘关系间的进程通信代码:
write:
1 #include <iostream> 2 #include <unistd.h> 3 #include <sys/mman.h> 4 #include <string> 5 #include <stdio.h> 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <fcntl.h> 9 10 using namespace std; 11 typedef struct _Student 12 { 13 int sid; 14 char name[20]; 15 }Student; 16 int main(int argc, char* argv[]) 17 { 18 if(argc != 2){ 19 cout << "please take file name!" << endl; 20 return -1; 21 } 22 int fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); 23 if(fd < 0){ 24 cout << "open failed" << endl; 25 } 26 ftruncate(fd, sizeof(Student)); 27 void* addr = mmap(NULL, sizeof(Student), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 28 if(addr == MAP_FAILED){ 29 cout << "mmap failed" << endl; 30 return -1; 31 } 32 Student *stu = (Student*)addr; 33 int num = 1; 34 while(1) 35 { 36 stu->sid = num; 37 sprintf(stu->name, "xiaoming--%3d", num++); 38 sleep(1); 39 } 40 if(munmap(addr, sizeof(Student)) < 0) 41 { 42 cout << "munmap error" << endl; 43 return -2; 44 } 45 return 0; 46 }
read:
1 #include <iostream> 2 #include <unistd.h> 3 #include <sys/mman.h> 4 #include <sys/types.h> 5 #include <sys/stat.h> 6 #include <fcntl.h> 7 8 using namespace std; 9 typedef struct _Student 10 { 11 int sid; 12 char name[20]; 13 }Student; 14 15 int main(int argc, char *argv[]) 16 { 17 if(argc != 2){ 18 cout << "please take file name!" << endl; 19 return -1; 20 } 21 int fd = open(argv[1], O_RDWR); 22 if(fd < 0){ 23 cout << "open failed" << endl; 24 } 25 26 void* addr = mmap(NULL, sizeof(Student), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 27 if(addr == MAP_FAILED){ 28 cout << "mmap failed" << endl; 29 return -1; 30 } 31 Student *stu = (Student*)addr; 32 while(1){ 33 cout << "sid = " << stu->sid << " name = " << stu->name << endl; 34 sleep(1); 35 } 36 return 0; 37 }