Linux下的进程间通信又称之为ipc 进程间通信可分为:管道、信号、消息队列、共享内存、信号量、套接字
| 日期 | 变更记录 |
|---|---|
| 2021-9-28 | 创建 |
无名管道管道仅存在于内存中,它是一个半双工的通信模型,具有固定的读端和写端,当一个管道建立时,会创建两个文件描述符,分别为fd[0]和fd[1],fd[0]用于读管道,fd[1]用于写管道
1. 父子进程 2. 兄弟进程 有名管道只能用于具有亲缘关系的进程之间的通信。是一个半双工的通信模式,具有固定的读端和写端,只存在于内存中
Example 1. 父子进程有名管道可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出,并且在文件系统中是可见的,该管道严格遵守先进先出规则,不支持lseek操作,用户可通过 mknod 管道名 p 来创建有名管道
#include2. 兄弟进程#include #include #include int main(int argc, char argv[]) { int fd[2]; char rBuf[20]; int rCnt, wCnt; if (pipe(fd) < 0) { printf("Pipe Create Error ! n"); exit(1); } else if ((pipe(fd)==fork()) == 0) // 子进程 { close(fd[1]); rCnt = read(fd[0], rBuf, sizeof(rBuf)); if (rCnt < 0) { printf(" Son Read Error ! n "); exit(1); } else { printf("Read Success [%d] Content is : %s ", rCnt, rBuf); } close(fd[0]); } else // 父进程 { close(fd[0]); wCnt = write(fd[1], "Hello Son !", sizeof("Hello Son !")); if (wCnt < 0) { printf("Father Write Error ! n"); exit(1); } else { printf("Write Success ! n"); } close(fd[1]); } }
#include3. 有名管道#include #include #include #include int main(int argc, char argv[]) { int fd[2]; int rCnt, wCnt, ret, ret1; char rBuf[20]; if (pipe(fd) < 0) { printf("Pipe Create Error ! n"); exit(1); } ret = fork(); if (ret == 0) { close(fd[1]); rCnt = read(fd[0], rBuf, sizeof(rBuf)); if (rCnt < 0) { printf(" Son_1 Read Error ! n "); exit(1); } else { printf("Son_1 Read Success [%d] Content is : %s ", rCnt, rBuf); } close(fd[0]); } else { ret1 = fork(); if (ret1 == 0) { close(fd[0]); wCnt = write(fd[1], "Hello Son !", sizeof("Hello Son !")); if (wCnt < 0) { printf("Son_2 Write Error ! n"); exit(1); } else { printf("Son_2 Success ! n"); } close(fd[1]); } else // 父进程 { close(fd[0]); close(fd[1]); waitpid(ret, NULL, 0); waitpid(ret1, NULL, 0); } } }
// r.c #include信号#include #include #include #include #include #include int main(int argc, char *argv[]) { int fd, rCnt; char rBuf[20] = {0}; if((mkfifo("/opt/myfifo", O_RDWR|O_CREAT) < 0) && (errno != EEXIST)) // 在opt下建立一个有名管道myfifo,判断是否建立成功 { perror("mkfifo:"); exit(0); } fd = open("/opt/myfifo", O_RDONLY); // 以只读的方式打开管道 if(fd < 0) { perror("open:"); } rCnt = read(fd, rBuf, 20); // 读取管道内容存放在rBuf中 printf("read(%d):%s", rCnt, rBuf); close(fd); return 0; } // w.c #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int fd; if((mkfifo("/opt/myfifo", O_RDWR|O_CREAT) < 0) && (errno != EEXIST)) // 在opt下建立一个有名管道myfifo,判断是否建立成功 { perror("mkfifo:"); exit(0); } fd = open("/opt/myfifo", O_WRONLY); // 以只写的方式打开管道 if(fd < 0) { perror("open:"); } if(argc == 1) { printf("请传递要写入管道的值n"); exit(1); } else { write(fd, argv[1], strlen(argv[1])); printf("write(%d):%s", (int)strlen(argv[1]), argv[1]); } close(fd); return 0; }
信号可以直接进行用户空间和内核进程之间的交互,如果一个信号被阻塞,那么该信号会被延迟,直到非阻塞才会被传递给进程
#include共享内存#include #include #include #include void sig_killRaise() { int ret; int sigFlag; ret = fork(); if (ret < 0) { perror("fork:"); exit(0); } else if (ret == 0) //子进程 { printf("I am son!n"); while (1) { printf("helpn"); sleep(1); } printf("son endn"); } else //父进程 { printf("I am you fa !n"); sleep(5); sigFlag = kill(ret, SIGKILL); if (sigFlag == 0) { waitpid(ret, NULL, 0); } else { perror("kill:"); } } } void fun(int sig_no) { printf(" i am here"); if (sig_no == SIGINT) { printf("get ctrl + cn"); } } int main(int argc, char *argvp[]) { printf("signal start!n"); sig_killRaise(); signal(SIGINT, fun); }
共享内存是一种最为高效的进程间通信方式。总体可分为三部分,第一部分是创建共享内存,第二步是映射共享内存,第三步是撤销映射的操作
//w.c // 创建共享内存 // 映射共享内存 #include消息队列#include #include #include #include int main(int argc, char *argv[]) { // 创建共享内存 int shmid, shmdet, fd[2], wCnt, rCnt; char *shmadd; char rBuf[20]; shmid = shmget((key_t)55, 2048, 777); if (shmid < 0) { perror("Shmget error ! n"); exit(0); } else { printf("Shmget Success , %d !n", shmid); } // shmctl() // 映射共享内存 shmadd = shmat(shmid, 0, 0); // 成功返回的是一个地址 if (shmadd < (char *)0) { perror("Shmadd error ! n "); exit(0); } else { printf("Shmat Success , %x !n", shmadd); while (1) { printf("input:"); gets(rBuf); fflush(stdin); memcpy(shmadd, rBuf, sizeof(rBuf)); if(!strcmp(shmadd,"end")) { break; } } } shmdet = shmdt(shmadd); if (shmdet < 0) { perror("Shmdet Error ! n "); exit(0); } else { printf("Shmdet Success %d !n", shmdet); } } //r.c // 创建共享内存 // 映射共享内存 #include #include #include #include #include int main(int argc, char *argv[]) { // 创建共享内存 int shmid, shmdet, shmcle, wCnt, rCnt; char *shmadd; char rBuf[20]; shmid = shmget((key_t)55, 2048, 777); if (shmid < 0) { perror("Shmget error ! n"); exit(0); } else { printf("Shmget Success , %d !n", shmid); } // shmctl() // 映射共享内存 shmadd = shmat(shmid, 0, 0); // 成功返回的是一个地址 if (shmadd < (char *)0) { perror("Shmadd error ! n "); exit(0); } else { while (1) { printf("Shmat Success , %s !n", shmadd); if (!strcmp(shmadd, "end")) { break; } } } shmdet = shmdt(shmadd); if (shmdet < 0) { perror("Shmdet Error ! n "); exit(0); } else { printf("Shmdet Success %d !n", shmdet); } shmcle = shmctl(shmid, IPC_RMID, 0); if (shmcle < 0) { perror("Shmctl Error !n"); exit(0); } else { printf("Shmctl Success %d !n", shmcle); } }
函数目录 pipe mkfifo errno sig(信号) kill raise alarm pause signal shmget shmat shmdt shmctl消息队列具有有名管道的一定特性,但是它可以实现消息的随机查询,比有名管道具有更大的优势



