进程间通信时什么?
在Linux下每一个进程都拥有自己的虚拟的值空间, 因此进程与进程之间都是相互独立的, 所以当两个进程之间想要进行数据交互的时候, 他们自身是没有办法完成的, 所以操作系统为进程之间提供了进程间的通信方式, 也就是为进程之间提供了一个公共的媒介.
进程间通信所完成的任务
- 进程间数据传输
- 数据共享
- 进程控制
- 事件通知
进程间通信方式
管道在进程间通信主要实现的就是进程间数据的传输 , 并且他是一个半双工通信, 意为 : 管道中传输的数据,只能从一端单项的流向另外一端.
管道的操作是一个IO操作 , 当管道创建成功之后, 会返回句柄–该句柄为两个文件描述符, 其中一个用于读, 另一个用于写.
管道的创建是用户通过调用系统调用接口, 操作系统在内核态创建出管道供进程之间使用.
匿名管道/命名管道 : 很显然, 命名管道就是拥有名字的管道,进程在对其进行使用时, 可以直接通过名字来使用, 而匿名管道在创建之后,是没有名字的, 因此一个金层想要操作该管道, 必须满足此进程为创建匿名管道进程的子进程. 因为具有亲缘关系的进程之间的PCB是复制而来的.
总而言之: 匿名管道,只能用于具有亲缘关系的进程间通信. 命名管道可以用于任意的进程间通信
管道的原理
管道实际上是操作系统在内核中提供的一块缓冲区(只要进程能够访问到这块缓冲就可以实现通信)
通过代码的实现我们可以发现这块缓冲区的大小大致为64K;
//创建匿名管道
int pipe(int pipefd[2]);
//pipefd[2]中,我们定义pipefd[0]用来读取数据, pipe[1]用来写入数据
int main(){
int pipefd[2];
int ret=pipe(pipefd);
if(ret<0){
perror("crtater pipe error");
return -1;
}
//pipefd[0]---用来读取数据 pipefd[1]---用来写入数据;
int pid=fork();
if(pid<0){
perror("creater fork error");
return -1;
}else if(pid==0){
//父进程--写入数据
int i=0;
while(1){
char *str="Today wa stree men not goto study!";
i+=write(pipefd[1],str,strlen(str));
printf("%d\n",i);
if(ret<0){
perror("write error");
return -1;
}
}
}
else{
//子进程---读取数据
char buf[1024]={0};
int ret=read(pipefd[0],buf,1023);
if(ret<0){
perror("read error");
return -1;
}
printf("buf---[%s]\n",buf);
}
return 0;
}
管道的读写特性
- 若管道中没有数据, 则read会阻塞,直到读取到数据(有数据写入管道)
- 若管道中数据满了, 则write会阻塞, 直到有空闲空间(有数据被取走了)
- 若所有读端被关闭, 则write会触发异常—发送SIGPIPE信号(导致进程退出)
- 若所有写端被关闭, 则read读完数据之后不会阻塞直接返回0
因此, 进程在操作管道的时候, 如果没有用到某一段, 则要把这一端关闭掉