對消息隊列的理解
消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法,傳輸的數據塊類型可以由消息接收者自行解析,消息隊列不僅可以用在不同進程間通信,也可以在不同線程間通信,具體看實際應用
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);
}