Linux进程间通信(上)
目录
一、无名管道PIPE
二、有名管道FIFO
三、内存映射mmap
进程间通信IPC(Inter Process Communicating)主要包括:
无名管道pipe、有名管道fifo、内存映射mmap、共享内存shm,消息队列msg、信号signal、套接字socket(多机之间,多用于网络编程)
一、无名管道PIPE
管道,单工通信,通常指无名管道(无名在于它是伪文件),存在(运行)内存中,只能用于具有亲缘关系的父子进程或兄弟进程(管道可共享于2个进程以上),因为管道数据是通过队列来维护的,一端固定只能读或写,管道建立时会创建两个文件描述符分别用于读写管道,所以只能用文件IO来操作,管道中的数据只能读一次,再读也没内容
int pipe(int fd[2]);
@param: 大小为2的int型数组,用来保存创建的两个文件描述符,fd[0]用来读、fd[1]用来写
@return:成功返回0,失败返回-1
读写特性:
1.读管道:
(1)管道中有数据,read从头读数据,返回实际读到的字节数
(2)管道中无数据且写端没有关闭时,read阻塞等待数据写入;写端关闭时,read返回0
2.写管道:
(1)读端全部关闭,“管道会发生爆裂”,进程异常终止,可捕捉SIGPIPE来让进程不终止
(2)读端没有全部关且管道未满,正常追加写入,write返回实际写入字节数;管道满了(大小64K),write阻塞
二、有名管道FIFO
一种文件类型,特殊文件,有路径名与之关联,但数据存在运行内存中(ls -la命令查看文件大小始终为0),可在任意无关进程之间交换数据,一端只读或只写,半双工通信,不支持lseek操作,遵循先进先出,同样,FIFO中的数据读一次就清空了,读FIFO从头读,写FIFO追加写
功能:创建或打开fifo
int mkfifo(char *pathname, mode_t mode)
@param: pathname 创建时给FIFO取个名
打开时指定FIFO
mode 创建时,mode不用加O_CREAT,直接赋值权限即可
打开时,mode设置O_WRONLY/O_RDONLY/O_RDWR 三选一
@return:成功返回0,失败返回-1(若存在同名fifo,创建失败,errno置EEXIST)
注意事项:
open fifo时,某进程只读或只写打开(mode设置O_WRONLY/O_RDONLY),会默认阻塞。若mode中或上O_NONBLOCK,则为非阻塞状态。
1)读写进程都默认阻塞时:先运行写或者读进程(被阻塞),再运行读或者写进程,不再阻塞,可以正常读写。
2)读进程非阻塞时:先运行写进程(被阻塞),再运行读进程,可以正常读写;先运行读进程,直接崩溃,因为没数据的情况下还不阻塞读!!!
3)写进程非阻塞时:只能先运行读进程,再运行写进程
关于数据完整性,多个进程写同一个管道时,如果写入数据长度<=4K,要么全部写入,要么一个字节都不写入(遵循先进先出);如果写入数据长度过长会导致数据交错
三、内存映射mmap
内存映射可以通过mmap()映射普通文件,将一个磁盘文件映射到进程自身的地址空间中,进程访问它通过返回的指针即可,不必调用read/write,全双工通信,因为访问内存的时间是纳秒级的,而访问磁盘是毫秒级的,大大提升了通信效率,适合于需要频繁读写大文件的场景
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
功能:申请创建 文件的内存映射区
@param:
addr 映射区目的地址,一般设置为NULL,操作系统自动分配,可通过返回值获取
length 必须>0 映射区的字节数,从文件开头offset个字节开始算起
prot 指定共享内存的访问权限 PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE
flags 常用的有:MAP_SHARED共享的、MAP_PRIVATE私有的,频繁访问磁盘操作时、MAP_ANOYMOUS匿名映射(用于无fd文件,比如父子进程间通信)
fd 文件描述符,匿名映射时为-1
offset 偏移量,指从文件头偏移offset个字节开始映射,一般都给0表示完整映射到映射区
@return:
成功返回映射区的地址,后续的读写操作通过这个地址
失败返回MAP_FAILED
int munmap(void *addr, size_t length)
功能:释放内存映射,即断开连接
@param: addr 映射区首地址 length 映射区大小
注意事项:
创建映射区出错概率很高,应养成返回值查错习惯!
flags为MAP_SHARED时,要求指定的共享内存访问权限<=open的文件权限;为MAP_PRIVATE时,只需要文件有可读权限即可,操作仅对内存有效,不会写入到磁盘,且不能在进程间共享
要映射的文件大小必须>0,否则会报错“总线错误”,系统所分配的映射区大小是以4K(一页内存大小)为单位的,文件大小<4K,系统仍分配4K,超过文件大小的范围可以访问,但仅仅是访问,无法真正写入文件
共享内存映射成功后,可以立即关闭文件,对后续共享内存的操作无影响
offset的偏移量必须为0/4K的整数倍