对消息队列的理解
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,传输的数据块类型可以由消息接收者自行解析,消息队列不仅可以用在不同进程间通信,也可以在不同线程间通信,具体看实际应用
linux系统提供了几个系统调用方便应用层调用,以下为消息队列用到的几个系统调用
msgget()函数
原型 |
意义 |
int msgget(key_t, key, int msgflg); |
创建和访问一个消息队列 |
参数 |
意义 |
key |
键来命名某个特定的消息队列 |
msgflg |
权限标志,表示消息队列的访问权限, 和IPC_CREAT做或操作,当队列不存在时创建,否则打开 |
msgsnd()函数
原型 |
意义 |
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); |
把消息添加到消息队列中 |
参数 |
意义 |
msgid |
由msgget函数返回的消息队列标识符 |
msg_ptr |
指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数将用这个成员来确定消息的类型 |
msg_sz |
msg_ptr指向的消息的长度, 注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度 |
msgflg |
用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情,0为阻塞 |
msgrcv()函数
原型 |
意义 |
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg); |
从消息队列获取消息 |
如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息
参数 |
意义 |
msgid |
由msgget函数返回的消息队列标识符 |
msg_ptr |
和msgsnd一样,但指向准备接收消息的指针 |
msg_st |
和msgsnd一样,msg_ptr指向的消息的长度, 注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度 |
msgtype |
可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息 |
msgflg |
用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情,0为阻塞 |
msgctl()函数
原型 |
意义 |
int msgctl(int msgid, int command, struct msgid_ds *buf); |
该函数用来控制消息队列 |
参数 |
意义 |
msgid |
由msgget函数返回的消息队列标识符 |
command |
command是将要采取的动作,它可以取3个值, IPC_STAT,IPC_SET,IPC_RMID |
buf |
指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构 |
command |
意义 |
IPC_STAT |
把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值 |
IPC_SET |
如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值 |
IPC_RMID |
删除消息队列 |
消息队列实现:
github源码
#include "msgqueue.h"
MESSAGEQ_ID create_msgqueue(char * name)
{
char syscmd[32] = {0x00};
char filename[32] = {0x00};
snprintf(filename, sizeof(filename), "/tmp/%s.msgq", name);
snprintf(syscmd, sizeof(syscmd), "rm -f %s", filename);
system(syscmd);
snprintf(syscmd, sizeof(syscmd), "touch %s", filename);
system(syscmd);
key_t key = ftok(filename, 0x01);
MESSAGEQ_ID id = msgget(key,IPC_CREAT | 0755);
return id;
}
bool msgqueue_post(MESSAGEQ_ID msgqid, uint8_t * msg, uint8_t msglen)
{
MsgQueue_t Msgs =
{
.msgtype = 1,
.msgbuff = {0},
};
if(msg == NULL || msglen == 0 || msglen > sizeof(Msgs.msgbuff))
return false;
memcpy(Msgs.msgbuff, msg, msglen);
msgsnd(msgqid, &Msgs, sizeof(Msgs.msgbuff), 0);
return true;
}
bool msgqueue_wait(MESSAGEQ_ID msgqid, uint8_t * msg, uint8_t msglen)
{
MsgQueue_t Msgs;
if(msg == NULL || msglen == 0 || msglen > sizeof(Msgs.msgbuff))
return false;
msgrcv(msgqid, &Msgs, sizeof(Msgs.msgbuff), 0, 0);
memcpy(msg, Msgs.msgbuff, msglen);
return true;
}
uint32_t msgqueue_getSize(MESSAGEQ_ID msgqid)
{
struct msqid_ds buffer;
msgctl(msgqid, IPC_STAT, &buffer);
return buffer.msg_qnum;
}
void msgqueue_delete(MESSAGEQ_ID msgqid)
{
msgctl(msgqid, IPC_RMID, NULL);
}