进程间通信方式(IPC)
进程间通信(Inter process communication,简称IPC)指的是进程之间的信息交换,进程间通信的方式有很多,比如管道通信、信号通信、共享内存、消息队列、信号量组、POSIX信号量等。
进程间通信可以达到数据传输、共享资源、控制进程等目的,方便用户对进程进行控制和管理。
当然,Linux系统中这么多种进程间的通信方式并不是一同出现的,而是在不同时期被设计出来,Linux系统属于类Unix系统,所以Linux系统继承了很多Unix系统的设计,比如Unix系统的System-V版本中就引入了三种进程间通信方式,分别是消息队列、共享内存、信号量组。这三种通信方式也被称为System-V IPC对象。
消息队列的概念
-
Linux系统中消息队列(Message Queue)是进程间通信的一种方式,这种通信机制的好处是可以传输指定类型(用户可以自行定义)的数据,相同类型的数据根据到达顺序在队列中进行排队。
-
不同类型的数据不能处于同一个队列中,也就是说系统中可能存在多个消息队列,每个消息队列中的数据类型都是不同的,所以用户打算读取消息队列中的数据时也需要指定数据类型,才可以从存储该类型数据的消息队列中读取有效数据。
如何指定某个消息队列进行消息传输?
Linux系统下每个被创建的消息队列都具有独属于自己的一个Key值,进程可以通过指定消息队列的Key值来选择消息队列进行数据传输。
可通过shell命令:ipcs -a来查看系统下所有IPC对象的信息
消息队列的建立
用户可通过Linux系统提供的msgget()函数接口打开或者创建一个消息队列。
-
第一个参数需要传入一个key_t的值,也就是对应的要创建的消息队列的key值(用户可通过ftok函数自行指定key值)
-
第二个参数需要指定消息队列的标志/权限,IPC_CREAT为消息队列不存在则创建,IPC_EXCL为消息队列存在则函数调用失败,用9字节进行权限设置(参考open函数的made类型)
-
成功返回消息队列的标识符,失败则返回-1并设置错误码
shell命令ipcmk也可用于创建IPC对象
消息队列的数据收发
Linux系统中提供了msgsnd()的函数接口,用户利用该函数可以向指定的消息队列发送信息。
msgrcv()用于数据读取,用户利用该函数可以向指定的消息队列读取信息
数据发送——msgsnd()
-
第一个参数msgid指消息队列的标识符,通过msgget函数返回
-
第二个参数msgp指向struct msgbuf类型的结构体指针,mtype指消息类型,mtext指消息正文
-
第三个参数msgsz指消息正文的大小。该值必须为非负整数
-
第四个参数msgflg指消息队列的标志。IPC_NOWAIT不阻塞,此时当待写入信息大于消息队列长度时,函数直接返回并报错。默认阻塞情况下,会阻塞到消息队列的容量足够容纳待写入数据时解除阻塞。
数据接收——msgrcv()
-
第一个参数msgid指消息队列的标识符,通过msgget函数返回
-
第二个参数msgp指存放消息的缓存地址,该地址下存储的是struct msgbuf类型结构体
-
第三个参数msgsz指的是存放消息的缓存的大小,按照字节计算,如果消息正文的大小大于用户设置的缓存大小,则根据msgflg是否为MSG_NOERROR进行判断,如果msgflg设置为MSG_NOERROR ,则可以读取对应字节的消息,如果msgflg没有设置,则无法读取消息并报错。
-
第四个参数:msgtyp指的是要接收消息的类型,在调用msgsnd函数时构造的消息结构体中有该成员的值。
- 等于0:不区分类型返回MSG中的第一个消息
- 大于0:读取类型为指定msgtyp的第一个消息(若msgflg被配置了MSG_EXCEPT则读取除了类型为msgtyp以外的第一个消息)
- 小于0:读取类型小于等于msgtyp绝对值的第一个具有最小类型的消息。(例如当MSG对象中有类型为3、1、5类型消息若干条,当msgtyp为-3时,类型为3的第一个消息将被读取。)
-
第五个参数:msgflg指的是接收消息选项,如果msgflg设置为0,指的是默认接收模式,在MSG中无指定类型消息时阻塞。
- IPC_NOWAIT:非阻塞接收模式,当MSG中没有指定类型时直接退出函数。
- MSG_EXCEPT:读取除msgtyp以外的第一个消息
- MSG_NOERROR:若待读取的消息尺寸比msgsz大,则只返回msgsz大小的部分,其余部分丢弃
消息队列的属性控制
IPC对象是一种持久性资源,如果没有明确的删除掉IPC对象,则IPC对象是不会自动从内存中消失的。用户除了可以使用命令的方式删除,也可以使用函数来删除。
Linux系统中提供了一个名称叫做msgctl的函数接口,用户可以利用该函数实现获取消息队列的属性信息、设置消息队列的属性信息、删除消息队列等操作。
消息队列的删除
-
通过shell命令:ipcrm
-
通过函数接口msgctl