目录
原理
实现进程通信的目的:
数据传输!
共享数据!
通知事件!
资源共享!
进程控制!
早期linux进程间信号(IPC)有3个部分:
- UNIX进行通信方式:管道、FIFO、信号;
- System V进程通信: System V消息队列、System V信号量、 System V共享内存;
- POSIX进程间通信:posix消息队列、posix信号量、posix共享内存;
目前Linux进程通信方式:
- 管道(pipe)和命名管道(FIFO);
- 信号(signal);
- 消息队列;
- 共享内存;
- 信号量;
- 套接字(socket);
管道通信:
- 本地计算机的两个进程之间的通信而设计的,管道建立后,获取两个文件的描述符:一个用于写,一个用于读;
- 通过pipe系统调用;
- 管道是单工的,数据只向一个方向流动,双向流动要建立两个管道;
- 数据的读出和写入:一个进程向管道中写的内容被管道另一端读出。写入的内容每次都添加到管道的缓存区的末尾,并且每次都是从缓存区的头部读取数据。
【注意:管道实际上是创建到计算机内核当中的缓存】
管道分类:
匿名管道:
- 在关系进程中进行(父进程和子进程、兄弟进程直接);
- 由pipe系统调用,管道由父进程建立;
- 管道位于内核空间,其实是一块缓存;
命名管道(FIFO):
- 两个进程之间没有任何关系,本质上是内核中的一块缓存,另外在文件系统中以一个特殊的设备文件(管道文件)存在。
- 通过系统调用mkfifo创建;
【注意可以通过操作这个管道文件就可以了,他会自动同步到缓存中】
注意:
fork子进程后,会复制父进程的数据(代码段,数据段,堆栈等),所以fd(文件描述符)也会被复制
fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
栗子
下面是源码,要注意:
- fd[0]:为pipe的读端口;fd[1]:为pipe的写端口;
- 要注意,用完,或不用端口就把他关掉;
- 父进程要回收下子进程、wait()是等待进程结束;
源码如下:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(void){
int fd[2];
if(pipe(fd) < 0){
perror("pipe error!");
exit(1);
}
pid_t pid;
if((pid = fork()) < 0){
perror("fork error");
exit(1);
}
else if(pid >0 ){ // parent process
close(fd[0]);
int start = 1, end = 100;
//往管道中写数据
if(write(fd[1], &start, sizeof(int)) != sizeof(int)){
perror("write error");
exit(1);
}
if(write(fd[1], &end, sizeof(int)) != sizeof(int)){
perror("write error");
exit(1);
}
close(fd[1]);
wait(0);
}
else{ //child process
close(fd[1]);
int start, end;
if(read(fd[0], &start, sizeof(int)) < 0){
perror("read error");
exit(1);
}
if(read(fd[0], &end, sizeof(int)) < 0){
perror("read error");
exit(1);
}
close(fd[0]);
printf("child process read start: %d , end: %d \n", start, end);
}
exit(0);
}
程序运行截图如下: