Linux中消息隊列的使用
今天帶小伙伴們學(xué)習(xí)了消息隊列相關(guān)的內(nèi)容,先簡單介紹下消息隊列,然后對消息隊列相關(guān)的結(jié)構(gòu)及函數(shù)進行學(xué)習(xí),最后擼代碼使用一下這些函數(shù)使用一下消息隊列,希望對大家有所幫助哈!
1 消息隊列的概念及使用過程
1)消息隊列的概念
消息隊列就是一個消息的鏈表。一條消息可以看作一個數(shù)據(jù)記錄,此數(shù)據(jù)具有特定的格式。
進程可以按照特定的規(guī)則向隊列中添加(寫入)消息;其他的進程則可以從消息隊列中讀走消息。
2)消息隊列的應(yīng)用場景
消息隊列本身就是IPC通信中的內(nèi)容,所以它主要用于進程間的通信。
消息有讀寫,所以發(fā)送的消息可以用于動作的通知信號,也可以接收數(shù)據(jù)然后做其他處理。
2 消息隊列相關(guān)的結(jié)構(gòu)及函數(shù)
0)消息隊列相關(guān)的結(jié)構(gòu)
每個隊列都有一個msqid_ds結(jié)構(gòu)與其相關(guān)聯(lián),結(jié)構(gòu)如下。
- struct msqid_ds
 - {
 - struct ipc_perm msg_perm; // 消息隊列的存取權(quán)限以及其他一些信息
 - time_t msg_stime; // 最近一次隊列接受消息的時間
 - time_t msg_rtime; // 最近一次從隊列中取出消息的時間
 - time_t msg_ctime; // 最近一次隊列發(fā)生改動的時間
 - unsigned long __msg_cbytes; // 隊列中消息的占用內(nèi)存的字節(jié)數(shù)
 - msgqnum_t msg_qnum; // 隊列中當前的消息數(shù)
 - msglen_t msg_qbytes; // 隊列所占用內(nèi)存的最大字節(jié)數(shù)
 - pid_t msg_lspid; // 最近一次向隊列發(fā)送消息的進程的pid msgsnd
 - pid_t msg_lrpid; // 最近一次從隊列中取出消息的進程的pid
 - };
 
- struct ipc_perm
 - {
 - key_t key;
 - ushort uid; // 用戶id,有效的用戶ID和有效的組id(euid和egid)
 - ushort gid;
 - ushort cuid; // 創(chuàng)建者的euid和egid
 - ushort cgid;
 - ushort mode; // 訪問模式參見模式標志
 - ushort seq; // IPC對象使用頻率信息
 - };
 
1)msgget函數(shù)
msgget函數(shù)用于創(chuàng)建或打開消息隊列。
① 函數(shù)原型。
- int msgget(key_t key,int msgflg)
 
② 頭文件。
- include <sys/ipc.h>
 - include <sys/msg.h>
 - include <sys/types.h>
 
③ 參數(shù)。
key:鍵值。
msgflg:打開標志。IPC_CREAT:表明新創(chuàng)建的一個消息隊列。
④ 返回值。
成功:返回消息隊列的id。
失?。?1。
2)msgsnd函數(shù)
msgsnd函數(shù)用于發(fā)送消息,即寫消息到消息隊列。
① 函數(shù)原型。
- int msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg)
 
② 頭文件。
- include <sys/ipc.h>
 - include <sys/types.h>
 - include <sys/msg.h>
 
③ 參數(shù)。
msgid:消息隊列的id。
msgp:指向要發(fā)送的消息。
msgsz:消息的長度。
msgflg:標志位。
④ 返回值。
成功:0。
失?。?1。
3)msgrcv函數(shù)
msgrcv函數(shù)用于讀消息隊列,即從消息隊列接收消息。
① 函數(shù)原型。
- int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
 - ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,intmsgflg)
 
② 頭文件。
- #include <sys/ipc.h>
 - #include <sys/types.h>
 - #include <sys/msg.h>
 
③ 參數(shù)。
msqid:消息隊列的id。
msgp:存放消息。
msgsz:希望取到的消息的最大長度。
msgtyp:消息的類型,分下面三種情況:
當 msgtyp = 0:忽略類型,直接取隊列中的第一條消息。
當 msgtyp > 0: 取消息隊列中類型等于msgtyp的第一條消息。
當 msgtyp < 0: 取類型比msgtyp的絕對值要小或等于的消息,如果有多條消息
滿足該條件,取類型最小的一條。
④ 返回值。
成功:實際接收到的消息的數(shù)據(jù)長度。
失?。?1。
4)msgctl函數(shù)
msgctl函數(shù)用于操作消息隊列,比如進行消息隊列的刪除等等。
① 函數(shù)原型。
- int msgctl(int msqid,int cmd,struct msqid_ds *buf)
 
② 頭文件。
- #include <sys/ipc.h>
 - #include <sys/msg.h>
 - #include <sys/types.h>
 
③ 參數(shù)。
msqid:消息隊列的id。
cmd:消息隊列的操作命令,此參數(shù)指定對msqid指定的隊列要執(zhí)行的命令。
IPC_STAT:取此隊列的msqidds結(jié)構(gòu),并將它存放在buf指向的結(jié)構(gòu)中。
IPCSET:將字段msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes從buf指向的結(jié)構(gòu)復(fù)制到與這個隊列相關(guān)的msqid_ds結(jié)構(gòu)中。
此命令只能由下列兩種進程執(zhí)行:
一種是其有效用戶ID等于msg_perm.cuid或msg perm.uid。
另一種是具有超級用戶特權(quán)的進程。只有超級用戶才能增加msg_qbytes的值。
IPC_RMID:從系統(tǒng)中刪除該消息隊列以及仍在該隊列中的所有數(shù)據(jù)。這種刪除立即生效。
仍在使用這一消息隊列的其他進程在它們下一次試圖對此隊列進行操作時,將得到EIDRM錯誤。
此命令只能由下列兩種進程執(zhí)行:
一種是其有效用戶ID等于msg_perm.cuid或msg_perm.uid。
另一種是具有超級用戶特權(quán)的進程。這3條命令(IPC_STAT、IPC_SET和IPC_RMID)也可用于信號量和共享存儲。
buf:獲取內(nèi)核中的msqid_ds結(jié)構(gòu),通常不用。
④ 返回值。
成功:0。
失?。?1。
3 實例代碼
下面用兩個進程,給大家演示下消息隊列的使用過程。
實例代碼如下,說明都在代碼注釋中了,圖片。
SendQueue.c。
- #include<stdio.h>
 - #include<sys/types.h>
 - #include<sys/ipc.h>
 - #include<sys/msg.h>
 - #include<string.h>
 - // 消息結(jié)構(gòu)體
 - struct msg
 - {
 - long msgtype; //消息的類型
 - char msgtext[1024]; //消息的長度
 - };
 - void main(int argc, char *argv[])
 - {
 - int msgid;
 - char str[256];
 - struct msg msgst;
 - key_t key = ftok("/tmp",600);
 - //創(chuàng)建消息隊列
 - msgid = msgget(key,0666 | IPC_CREAT);
 - //鍵盤輸入消息
 - while(1)
 - {
 - //獲取消息數(shù)據(jù)
 - printf("\nPlease enter a message to send,input 'end' to quit!\n\n");
 - scanf("%s",str);
 - strcpy(msgst.msgtext,str);
 - if(strncmp(str, "end", 3) == 0)
 - {
 - printf("\n");
 - break;
 - }
 - //發(fā)送消息
 - msgsnd(msgid,&msgst,sizeof(struct msg),0);
 - }
 - //輸出消息隊列
 - msgctl(msgid,IPC_RMID,0);
 - }
 
ReceiveQueue.c。
- #include <unistd.h>
 - #include <stdlib.h>
 - #include <stdio.h>
 - #include <string.h>
 - #include <errno.h>
 - #include <sys/msg.h>
 - // 消息結(jié)構(gòu)體
 - struct msg
 - {
 - long msgtype;
 - char msgtext[1024];
 - };
 - int main(int argc, char *argv[])
 - {
 - int RunFlag = 1; // 循環(huán)標志
 - int msgid = -1; // 消息id
 - long msgtp = 0; // 消息類型
 - struct msg msgst; // 消息結(jié)構(gòu)體變量
 - key_t key = ftok("/tmp",600); // 創(chuàng)建一個鍵值
 - msgid = msgget(key, 0666 | IPC_CREAT); //建立消息隊列
 - if(msgid == -1)
 - {
 - exit(1); // 異常退出
 - }
 - while(RunFlag) // 從隊列中獲取消息,直到遇到end消息為止
 - {
 - if(msgrcv(msgid,&msgst,sizeof(struct msg), msgtp, 0) == -1)
 - {
 - exit(1); // 異常退出
 - }
 - printf("\nThe message received is: %s\n\n",msgst.msgtext);
 - if(strncmp(msgst.msgtext, "end", 3) == 0) // 遇到end結(jié)束
 - {
 - RunFlag = 0; // 置退出循環(huán)標志
 - }
 - }
 - if(msgctl(msgid, IPC_RMID, 0) == -1) // 刪除消息隊列
 - {
 - exit(1); // 異常退出
 - }
 - exit(0); // 正常退出
 - }
 
編譯程序,先運行接收程序,再運行發(fā)送程序,輸入要發(fā)送的消息,退出輸入end。
① 兩個終端運行結(jié)果如下:
② 單個終端運行結(jié)果如下:
本文轉(zhuǎn)載自微信公眾號「嵌入式雜牌軍」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系嵌入式雜牌軍公眾號。


















 
 
 













 
 
 
 