1 进程间通信的引入
1.由于进程与进程之间具有独立性,有时候我们想让不同的进程进行数据传输,进程的独立性就会使得数据传输变得很困难;
2.因此只要有一种机制,能够让不同的进程看到同一份资源,就可以通过该资源进行信息交互,因此就有了进程间通信。
1.1 进程间通信介绍
1.进程间通信:在不同的进程间传播或交换信息。
2.进程间通信的方式:管道、消息队列、共享内存、信号量、socket(套接字)等。
3.进程间通信的本质:让不同的进程看到同一份资源。
1.2 进程间通信的目的
1.数据传输
2.资源共享
3.通知事件
4.进程控制
2 管道
1.管道通常指匿名管道,是Unix中最古老的进程间通信方式。
2.我们把从一个进程连接到另一个进程的一个数据流称为一个管道。
3.管道被抽象成一个文件,管道的本体是一段内存。
2.1 管道的特点
1.对于匿名管道来说,它只能用于具有亲缘关系的进程(父子、兄弟、爷孙等)进行进程间通信;
- 因为子进程的PCB是以父进程的PCB为模板拷贝的,PCB里面含有一个file*的结构体指针,该指针指向一个结构体,里面包含文件描述符表,文件描述符表是继承自父进程的,所以他们的文件描述符表的内容是一样的,即就是他们可以看到同一个资源。
2.管道只能进行单向通信,如果需要双向通信,则需要两个管道;
3.管道是基于数据流(字节流)的;
- 因为管道的读或写没有确定的大小,而面向数据报是有大小的。
4.管道的生命周期随进程;
- 因为管道的本体是一段内存,当进程退出这段内存也就没有了。
5.一般而言,内核会对管道的操作进行同步与互斥,即管道自带同步与互斥。
- 例如:如果写端向管道里面写数据,如果没有写完,则不允许读,否则会读错数据。
3 匿名管道
1.创建方式(pipe函数)
#include <unistd.h>
int pipe(int pipefd[2]); //pipe用于创建一个匿名管道,pipefd为输出型参数,是一个文件描述符组,pipefd[0]表示读,pipefd[1]表示写
返回值:成功返回0,失败返回-1
- 管道创建成功后,就会有两个文件描述符,一个用来读,一个用来写,通过文件描述符就可以往管道里面读写数据。
- 通过read和write函数就可以进行相关读写操作。
2.示例1:创建一个匿名管道
#include<stdio.h>
#include<unistd.h>
int main()
{
int fd[2];
int ret = pipe(fd);
if(ret == -1)
{
perror("pipe()");
return 1;
}
return 0;
}
3.示例2:从键盘读取数据,写入管道,再从管道读取数据写到屏幕(或标准输出)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<string.h>
int main()
{
//创建一个管道
int fd[2];
int ret = pipe(fd);
if(ret <0)
{
perror("pipe");
return -1;
}
while(1)
{
//从标准输入读数据
char buf[1024]={
0};
ssize_t s = read(0,buf,sizeof(buf)-1);
if(s < 0)
perror("read");