1.什么是IPC
a.进程间通信
i.InterProcess Communication
2.进程间通信常用的4种方式
a.管道-简单
b.信号-系统开销小
c.共享映射区 -(有无血缘关系的进程间通信都可以)
d.本地套接字 - 稳定
由于每个进程都有各自不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不见,所以进程之间要减缓数据必须通过内核,在内核中开辟一块缓冲区。内核提供这种机制称之为进程间通信。
3.父子进程永远共享的东西?
文件描述符
内存映射区
1.管道的概念
本质:
内核的缓冲区(内核里的一个空间)
伪文件 - 不占用磁盘空间(在硬盘上没有)
【因为它的操作跟文件IO操作一样,所以称之为伪文件】
特点:
两部分:
读端,写端,对应两个文件描述符
数据写端流入,读端流出。
数据是单向流动的–半双工
当操作管道的进程被销毁之后,管道自动释放了。
管道默认是阻塞的。【后端对管道操作就是对两个文件描述符的操作,而对文件描述符的操作就是文件的IO操作】
阻塞包括读和写。
①如果一个管道的写端一直在写,而读端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只写不读再次调用write会导致管道堵塞;
②如果一个管道的读端一直在读,而写端的引⽤计数是否⼤于0决定管道是否会堵塞,引用计数大于0,只读不写再次调用read会导致管道堵塞;
③而当他们的引用计数等于0时,只写不读会导致写端的进程收到一个SIGPIPE信号,导致进程终止,只写不读会导致read返回0,就像读到⽂件末尾⼀样。
文件的读写不是read和write的行为,而是对文件描述符对应的文件的行为。
2.管道的原理
内部实现方式:队列
环形队列【通过算法实现,本质是线性队列】
特点:先进先出
缓冲区的大小
默认4K
大小会根据实际情况做适当的调整,不会无限放大
3.管道的局限性
队列:
数据只能读取一次,不能重复读取。【读取就把数据弹出去了】
半双工:就是数据传输的方向是单向的
匿名管道:
适用于有血缘关系的进程
4.创建匿名管道
int pipe(int fd[2]);
fd-传出参数
fd[0]-读端
fd[1]-写端
5.父子进程使用管道通信
单个进程能否使用管道完成读写操作?
可以
父子进程间通信是否需要sleep函数?
父 写 --写的慢
子 读 – 读的快
不需要
父进程fork出子进程,子进程也有两个文件描述符指向同一管道。
父进程关闭fd[0],子进程关闭fd[1],即父进程关闭管道读端,子进程关闭管道写端(因为管道只支持单向通信)。父进程就可以往管道里写,子进程可以从管道里读。
6.兄弟进程使用管道通信
父进程关闭读和写
父亲 - 资源回收
7.管道的读写行为
读操作
read(fd)
(1)有数据
read(fd) - 正常读,返回读出的字节数
(2)无数据
1>写端全部关闭
2>没有全部被关闭
写操作
(1)读端全部关闭
管道破裂,进程被终止
内核会给当前进程发信号SIGPIPE【终止进程】
(2)读端没全部关闭
1>缓冲区写满了
2>缓冲区没有满
如何设置非阻塞?
默认读写两端都阻塞
设置读端为非阻塞pipe(fd)
fcntl - 变参函数
a)复制文件描述符 - dup
b)修改文件属性 - open的时候对应flag属性
设置方法:
//获取原来的flags
int flags=fcntl(fd[0],F_GETFL);
//设置新的flags
flags |= O_NONBLOCK;
//或者
//flags= flags|O_NONBLOCK;
fcntl(fd[0],F_SETFL,flags);
8.查看管道缓冲区大小
命令
ulimit -a
【还可查看最大可支持的文件描述符的个数、栈空间的大小】
函数
fpathconf
【可查看很多属性:Linux下路径最长可写多长、文件描述符有多少个字符】
long size = fpathconf(fd[0],_PC_PIPE_BUF);
1.特点
2.使用场景
没有血缘关系的进程间通信
3.创建方式
4.fifo文件可以使用IO函数进行操作
5.进程间通信
a.fifo文件 — myfifo
int fd = open("myfifo",O_RDONLY);
read(fd,buf,sizeof(buf));
close(fd);
b.b.c — write
int fd1 = open("myfifo",O_WRONLY);
write(fd1,"hello,world",11);
close(fd1);
作用:将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件。
函数原型:
void *mmap(
void* adrr, //映射区首地址,传NULL,内核
size_t length, //映射区的大小
//100byte -4k 都是4k的整数倍
//不能为0
//一般文件多大,length就指定多大
int prot, //映射区权限
//此处的权限要大于等于fd【文件描述符,open】的权限!!!
//PROT_READ -- 映射区必须要有读权限<重点>
//PROT_WRITE
//PROT_READ | PROT_WRITE
int flags, //标志位参数
//MAP_SHARED 修改了内存数据会同步到磁盘
//MAP_PRIVATE 修改了内存数据不会同步到磁盘
int fd, //文件描述符
//要映射的文件对应fd
//通过 open() 得到对应的fd
off_t offset //映射文件的偏移量
//作用:映射的时候后文件指针的偏移量
//必须是4k的整数倍
//通常为0
);
返回值:
映射区的首地址 – 调用成功
调用失败:MAP_FAILED
进程间通信
a.有血缘关系的
i.父子进程共享内存映射区
b.没有血缘关系的进程间通信
i.如何通信?
不能使用匿名映射的方式
只能借助磁盘文件创建映射区
不阻塞
ii.a(a.c) b(b.c)
a.c
int fd=open(“hello”);
void* ptr=mmap(,fd,0);
对映射区做读写操作
b.c
int fd1=open(“hello”);
void* ptr1=mmap(,fd1,0);
对映射区做读写操作
如果创建匿名映射区
mmap的时候:
第二个参数:指定映射区大小
第四个参数:需要添加MAP_ANON宏
第五个参数:-1
munmap - 释放内存映射区
函数原型:int munmap(void *addr,size_t length);
addr - - mmap的返回值,映射区的首地址
length - - mmap的第二个参数,映射区的长度
问题: