SystemV方案是在OS内核层面专门为进程间通信设计的一个方案,然后通过系统调用(system call)给用户提供通信接口。SystemV方案包含三种:共享内存、消息队列、信号量。
和System V 共享内存一样,OS为了管理这些消息队列,给每个消息队列配上了标识唯一性的编号msgid。消息队列中的消息则是以链表的形式被管理的。
目录
1、ftok
2、msgget
3、msgsnd
4、msgrcv
5、msgctl
1、ftok
System V共享内存里也用到了这个函数,该函数的作用是生成一个具有唯一性的ID。这里的ID不是消息队列的ID,因为消息队列是一份临界资源,为了避免该消息队列被无关线程访问,所以设置了房间密码,ftok的返回值则是 “ 房间密码 ”。
ftok函数的第一个参数:路径名
ftok函数的第二个参数:项目ID
返回值:成功返回具有唯一性的“房间密码”;失败返回 -1
关于这个函数无需想的太复杂,简单来说就是,从路径名中取出一部分,然后再从ID中取出一部分,最后再把两部分组合一下形成一个整数,我们就把这个整数当作“房间密码”
注意:ftok被不同进程调用,只要路径名和ID是一样的,生成的整数就是一样的
2、msgget
msgget函数的作用是通过上面的得到的房间密码创建一个消息队列 或者 拿到已有消息队列的ID。
第一个参数 key:“房间密码”
第二个参数 msgflag:创建消息队列的方式,同时设置权限
返回值:成功返回消息队列id,失败返回 -1
类似于write函数的第二个参数,属于位运算输入
IPC_CREAT:可以单独使用,如果共享内存不存在,则重新开辟,函数返回值是新开辟的共享内
存的ID;如果已经存在,则沿用已有的共享内存,函数返回值是已有的共享内存的
ID
IPC_EXCL:无法单独使用,要配合IPC_CREAT使用,即 IPC_CREAT | IPC_EXCL
IPC_CREAT | IPC_EXCL:如果共享内存不存在,则重新开辟,函数返回值是新开辟的共享内
存的ID;如果已经存在,则报错
IPC_CREAT | IPC_EXCL | 0664:开辟共享内存的同时,设置共享内存的访问权限
key_t key = ftok(".", 100);
// 如果消息队列不存在 (0664 —— rw-rw-r--)
int msghid = msgget(key, IPC_CREAT | IPC_EXCL | 0664);
// 如果消息队列已存在
int msghid = msgget(key, IPC_CREAT);
3、msgsnd
msgsnd函数的作用是向消息队列中添加一条消息。
第一个参数 msgid:消息队列ID,即msgget函数的返回值
第二个参数 msgp: 消息缓冲区的地址,也就是你要向消息队列中添加的消息,需要满足一定的格式。消息格式如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */ //
// 消息类型,在从消息队列取出消息的时候,可以根据消息类型来选择性地取消息
char mtext[1]; /* message data */
// 消息内容
};
第三个参数 msgsz:表示消息长度。这里的消息长度指的是上面这个结构体中buf成员所占字节数
第四个参数 msgflag:表示发送消息的方式。可选值如下:
可选值 | 含义 |
0 | 当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列 |
IPC_NOWAIT | 当消息队列已满的时候,msgsnd函数不等待立即返回,此时是以报错的形式返回。 |
返回值:成功返回0,失败返回-1
4、msgrcv
msgrcv函数的作用是从消息队列的队头取出一条消息。
第一个参数 msgid:消息队列id
第二个参数 msgp:输出型参数,表示消息缓冲区的地址。也就是你要把取出来的消息放在哪,同样需要使用指定格式。(数据格式详见msgsnd函数)
第三个参数 size:指定接收的消息长度。单位是字节。
第四个参数 msgtype:选择想要取出的消息类型(虽然叫做消息队列,但是不一定就是取出队头元素,也可以是取出具有相同消息类型中的第一个消息)。主要分为以下三种情况:
msgtype的值 | 解析 |
msgtype = 0 | 直接取出队头消息,不论是什么类型 |
msgtype > 0 | 从所有消息类型为msgtype的消息中,取出其中的第一条消息 |
msgtype < 0 | 接收类型小于等于 msgtype的绝对值的第一条消息。 |
补充:针对msgtype < 0做一些补充,假设消息队列里的消息类型有 1、3、4、5 四种类型的消息,如果msgtype = -4,绝对值是4,那就需要取出消息类型小于等于4的所有消息,因此,取出消息的消息类型必须是1、3、4类型。
第五个参数 msgflag:表示接收消息的方式。可选值如下:
可选值 | 含义 |
0 | 阻塞式接收消息 |
IPC_NOWAIT | 如果消息队列中没有消息,则立马返回,此时错误码为ENOMSG |
MSG_EXCEPT | 与msgtype配合使用,返回队列中第一个类型不为msgtype的消息 |
5、msgctl
msgctl 函数的作用是控制消息队列,可以用来销毁消息队列。
第一个参数msgid:消息队列id
第二个参数cmd:对消息队列执行的具体操作,如拷贝、查询、销毁等。可选值如下:
可选值 | 含义 |
IPC_STAT | 将消息队列的相关信息拷贝放到第三个参数 buf 中 |
IPC_RMID | 销毁消息队列 |
第三个参数 buf:消息队列缓冲区。比如 cmd 为IPC_STAT时,会把消息队列的相关信息拷贝到该缓冲区中。