IPC之消息队列
概念:
消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的。
系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。 消息队列就是一个消息的链表。每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。
相信看到这里的应该都知道pipe,我们来简单看看它们的优缺点:
优点和缺点
优点:
消息队列是两个不相关进程之间传递数据的有效渠道.
与命名管道相比,具有的优势是:
独立于发送以及接收进程而存在;
消除命名管道的打开以及关闭而存在的困难;
可以提前查看紧急信息;
避免命名管道的同步以及阻塞问题;
缺点:
与命名管道一样,每个数据块都有一个最大长度限制;
系统中所有队列包含的全部数据块长度也有一个上限;
msgmni 最大消息队列数 16
msgmax 最大消息长度(字节数) 8192
msgmnb 消息队列中的最大字节数 16384
如果想查看系统的消息队列,共享内存,信号量,可以用命令: ipcs
结构:
接下来2张图帮助大家更好理解内核中消息队列的结构:
IPC机制都会有这个对象
拥有者及权限对象
struct ipc_perm
{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};
用于管理消息队列的对象
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
struct msg * msq_first ;
struct msg * msq_last ;
};
相关函数:
1.获取key
- key:通信双方约定好的KEY值,32位的整形数据
- id :系统会为IPC分配一个唯一的ID,通信双方都需要知道ID才能使用当前IPC方法,创建者会返回当前ID值,
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id); //将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
. proj_id 子序列号
key 31-24 proj_id 低8位
key 23-16 st_dev属性的低8位
key 15-0 st_ino属性的低16位
2.创建消息队列(创建struct msqid_ds对象)
原型:int msgget(key_t key, int msgflg )
返回值:失败返回-1, 个数限制, 打开别人队列没权限。大于0 调用成功 返回已打开的消息队列ID标识。
参数:
key_t key //相当于文件名,由函数ftok生产
int msgflg //指定消息队列创建。一般是IPC_CREAT 0644 或者0 (为0 则代表由操作系统自动选择)
IPC_CREAT 找到当前的key对应的IPC,如果没有IPC则进行创建
IPC_EXCL 如果存在则返回失败
IPC_NOWAIT 返回值为当前ipc对应的id值
3.设置对象
原型:int msgctl(int msqid,int cmd, struct msqid_ds *buf)
参数:
cmd:
IPC_RMID 删除
IPC_SET 设置ipc_perm参数
IPC_STAT 获取ipc_perm参数
IPC_INFO 获取ipc信息 和ipcs
4.使用对象
参数:
void* msgp: //想写入消息队列数据的地址,是指向消息缓冲区的指针,此位置用来暂时存储发送接收消息,是一个用户可定义的通用结构,形态如下:
struct msgbuf
{
long mtype; //k接收类型,可看作消息队列通道号channel ,同时必须> 0
char mtext[100] //存放内容
};
size_t msgsz //消息大小, 不算上通道号大小
gbuf
{
long mtype; //k接收类型,可看作消息队列通道号channel ,同时必须> 0
char mtext[100] //存放内容
};
size_t msgsz //消息大小, 不算上通道号大小
int msgflg //一般输入0,由操作系统自行选择