进程间通信-消息队列
System V IPC
- IPC : Inter-Process Communication(进程间通讯)
- System V 是早期的unix 系统,曾经被称为 AT &T System ,是 unix 操作系统中比较重要的一个分支,现在0Linux 系统一般都支持 System V IPC
- System V IPC 对象共有三种
- 消息队列
- 共享内存
- 信号量
- System V IPC 是由内核维护的若干个对象,通过 ipcs 命名查询
每个 IPC 对象都有一个唯一的 ID,可以通过 ftok()函数生成,ftok 函数具体说明如下
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
函数原型
key_t ftok(const char *pathname, int proj id);
函数参数
- pathname: 文件路径名
- proj_id : 8 bit 的 id 整数0
函数返回值 - 成功: 返回合成的 key
- 失败 :-1,并设置 errno
注意: - key 由 文件的 inode 节点号 与 proj_id 构成
- inode 节点号 : 每个存在的文件操作系统都会有唯一的编号,通过 ls -i命令查看
消息队列简介
- 消息队列就是一个消息的列表,进程可以在消息队列中添加消息和的读取消息
- 消息队列具有一定的FIFO特性,具有无名管道与有名管道的各自的优势,可以支持任意两个进程的进程间通讯
- 消息队列是属于 sytem v ipc 的一种,由内核维护与管理 可以通过 ipcs -q 查看
二、创建消息队列
创建消息队列调用 msgget 函数
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
int msgget(key_t key, int msgflg);
函数参数
- key: 由 ftok 函数合成
- msgflg : 消息队列标志
- IPC_CREAT: 创建标志
- IPC_EXCL : 如果消息队列存在,则报错,errno 设置为 EEXIST
- 权限控制标志
函数返回值
- 成功 : 返回 消息队列 id
- 失败: 返回-1,并设置 errno
对于已经创建的消息队列,如果 key 一样,则直接获取这个消息队列ID,对于新创建的消息队列,每次消息队列的ID 不一定相同,即使key一致
删除消息队列
删除消息队列需要调用 msgctl 函数,具体信息如下
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
int msgctl(int msqid, int cmd, struct msqid ds *buf)
函数参数
- msqid : 消息队列 id
- cmd : 命令字
- IPC_STAT: 获取消息队列属性
- IPC_SET : 设置消息队列属性
- IPC_RMID : 删除消息队列,用此命今时,第三个参数为 NULL
- buf : 消息队列属性结构体对象指针
函数返回值 - 成功:
IPC_STAT,IPC_SET, and IPC_RMID 返回 - 失败: 返回-1,并设置 errno
创建一个消息队列,并打印消息队列 ID,然后删除消息队列,使用 ipcs 命令验证
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#define PATHNAME "."
#define PROID 10
int main(){
key_t key;
int msgid;
key = ftok(PATHNAME,PROID);
if(key == -1){
perror("[ERROR] ftok:");
exit(EXIT_FAILURE);
}
msgid = msgget(key,IPC_CREAT | 0666);
if(msgid == -1){
perror("[ERROR] msgget():");
exit(EXIT_FAILURE);
}
printf("msg id: %d\n",msgid);
sleep(10);
int ret = msgctl(msgid,IPC_RMID,NULL);
if(ret == -1){
perror("[ERROR] msgctl()");
exit(EXIT_FAILURE);
}
return 0;
}
发送消息
发送消息队列需要调用 msgsnd 函数
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
int msgsnd(int msqid, const void *msgp, size t msgsz, int msgflg);
函数参数:
- msgid : 消息队列 ID
- msgp : 消息结构体指针
- msgsz : 消息内容的长度
- msgflg : 消息队列标志,默认可以填 0
- IPC NOWAIT:可以设置非阻塞
函数返回值:
- IPC NOWAIT:可以设置非阻塞
- 成功 : 返回 0
- 失败 : -1,并设置 errno
消息结构定义形式如下
struct msgbuf {
long mtype;/* message type, must be > 0 */
char mtext[1]; /* message data */
}
- mtype: 消息类型
- mtext: 消息内容数组
接收消息
- 接收消息调用 msgrcv 函数
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
ssize_t msgrcv(int msqid, void *msgp, size t msgsz, long msgtyp, int msgflg);
函数参数 - msqid : 消息队列 id
- msgp : 消息结构指针
- msgsz: 消息内容的最大长度
- msgtyp : 消息类型
- =0: 获取消息队列中的第一条消息
- >0:返回消息队列中等于mtype 类型的第一条消息
- msgflg : 消息队列标志,默认可以填
IPC NOWAIT:可以设置非阻塞
函数返回值: - 成功: 返回实际读取消息内容的字节数
- 失败:-1并设置 errno
创建两个没有血缘关系的进程,使用 消息队列进行通讯