jmstemplate 获取队列id_学习Linux(38)消息队列
消息隊列、共享內存 和 信號量?被統(tǒng)稱為 system-V IPC,V 是羅馬數(shù)字 5,是 Unix 的AT&T 分支的其中一個版本,一般習慣稱呼他們?yōu)?IPC 對象,這些對象的操作接口都比較類似,在系統(tǒng)中他們都使用一種叫做 key 的鍵值來唯一標識,而且他們都是“持續(xù)性”資源——即他們被創(chuàng)建之后,不會因為進程的退出而消失,而會持續(xù)地存在,除非調用特殊的函數(shù)或者命令刪除他們。
消息隊列與信號的對比:
·?信號承載的信息量少,而消息隊列可以承載大量的數(shù)據(jù)
消息隊列與管道的對比:
·?消息隊列跟命名管道有不少的相同之處,通過與命名管道一樣,消息隊列進行通信的進程可以是不相關的進程,同時它們都是通過發(fā)送和接收的方式來傳遞數(shù)據(jù)的。在命名管道中,發(fā)送數(shù)據(jù)用write(),接收數(shù)據(jù)用read(),則在消息隊列中,發(fā)送數(shù)據(jù)用msgsnd(),接收數(shù)據(jù)用msgrcv()。它們對每個數(shù)據(jù)都有一個最大長度的限制。
·?消息隊列也可以獨立于發(fā)送和接收進程而存在,在進程終止時,消息隊列及其內容并不會被刪除。
·?管道只能承載無格式字節(jié)流,消息隊列提供有格式的字節(jié)流,可以減少了開發(fā)人員的工作量。
·?消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優(yōu)先級,接收程序可以通過消息類型有選擇地接收數(shù)據(jù),而不是像命名管道中那樣,只能默認地接收。
·?消息隊列可以實現(xiàn)消息的隨機查詢,消息不一定要以先進先出的順序接收,也可以按消息的類型接收。
消息隊列的實現(xiàn)包括創(chuàng)建或打開消息隊列、發(fā)送消息、接收消息和控制消息隊列這 4 種操作。其中創(chuàng)建或打開消息隊列使用的函數(shù)是 msgget(),這里創(chuàng)建的消息隊列的數(shù)量會受到系統(tǒng)可支持的消息隊列數(shù)量的限制;發(fā)送消息使用的函數(shù)是 msgsnd()函數(shù),它把消息發(fā)送到已打開的消息隊列末尾;接收消息使用的函數(shù)是msgrcv(),它把消息從消息隊列中取走,與 FIFO 不同的是,這里可以指定取走某一條消息;最后控制消息隊列使用的函數(shù)是 msgctl(),它可以完成多項功能。
想要使用消息隊列還需要包含以下頭文件:
#include
#include
#include
創(chuàng)建或獲取消息隊列ID
msgget()函數(shù)
int msgget(key_t key, int msgflg);
該函數(shù)的作用是得到消息隊列標識符或創(chuàng)建一個消息隊列對象并返回消息隊列標識符:成功返回隊列ID,失敗返回-1。在以下兩種情況下,msgget()函數(shù)將創(chuàng)建一個新的消息隊列:
1.?如果沒有與鍵值key相對應的消息隊列,并且flag中包含了IPC_CREAT標志位。
2.?key參數(shù)為IPC_PRIVATE。
·?key:消息隊列的關鍵字值,多個進程可以通過它訪問同一個消息隊列,其中有個特殊值 IPC_PRIVATE,它用于創(chuàng)建當前進程的私有消息隊列。
·?msgflg表示創(chuàng)建的消息隊列的模式標志參數(shù),在真正使用時需要與IPC對象存取權限(如0600)進行“|”運算來確定消息隊列的存取權限。msgflg有多種情況:如果為0則表示取消息隊列標識符,若該消息隊列不存在則函數(shù)會報錯;如果是?IPC_CREAT?&?msgflg?為真則表示:如果內核中不存在關鍵字與key相等的消息隊列,則新建一個消息隊列;如果存在這樣的消息隊列,返回此消息隊列的標識符,而如果為?IPC_CREAT?|?IPC_EXCL?為真則表示:如果內核中不存在鍵值與key相等的消息隊列,則新建一個消息隊列;如果存在這樣的消息隊列則報錯,這些參數(shù)是可以通過“|”運算符聯(lián)合起來的,因為它始終是int類型的參數(shù)。
該函數(shù)可能返回以下錯誤代碼:
·?EACCES:指定的消息隊列已存在,但調用進程沒有權限訪問它
·?EEXIST:key指定的消息隊列已存在,而msgflg中同時指定IPC_CREAT和IPC_EXCL標志
·?ENOENT:key指定的消息隊列不存在同時msgflg中沒有指定IPC_CREAT標志
·?ENOMEM:需要建立消息隊列,但內存不足
·?ENOSPC:需要建立消息隊列,但已達到系統(tǒng)的限制
使用該函數(shù)需要注意的以下幾點:
1.?選項 msgflg 是一個位屏蔽字,因此 IPC_CREAT、IPC_EXCL 和權限 mode 可以用位或的方式疊加起來,比如:?msgget(key,?IPC_CREAT?|?0666);?表示如果 key 對應的消息隊列不存在就創(chuàng)建,且權限指定為 0666,若已存在則直接獲取消息隊列ID。
2.?權限只有讀和寫,執(zhí)行權限是無效的,例如 0777 跟 0666 是等價的。
3.?當 key 被指定為 IPC_PRIVATE 時,系統(tǒng)會自動產(chǎn)生一個未用的 key 來對應一個新的消息隊列對象,這個消息隊列一般用于進程內部間的通信。
發(fā)送消息與接收消息
msgsnd()函數(shù)
這個函數(shù)的主要作用就是將消息寫入到消息隊列,俗稱發(fā)送一個消息。
函數(shù)原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函數(shù)傳入值:
msqid:消息隊列標識符。
msgp:發(fā)送給隊列的消息。msgp可以是任何類型的結構體,但第一個字段必須為long類型,即表明此發(fā)送消息的類型,msgrcv()函數(shù)則根據(jù)此接收消息。msgp定義的參照格式如下:
/*msgp定義的參照格式*/
struct s_msg{
????long type; ?/* 必須大于0,消息類型 */
char mtext[1]; ?/* 消息正文,可以是其他任何類型 */
} msgp;
msgsz:要發(fā)送消息的大小,不包含消息類型占用的4個字節(jié),即mtext的長度。
msgflg:如果為0則表示:當消息隊列滿時,msgsnd()函數(shù)將會阻塞,直到消息能寫進消息隊列;如果為IPC_NOWAIT則表示:當消息隊列已滿的時候,msgsnd()函數(shù)不等待立即返回;如果為IPC_NOERROR:若發(fā)送的消息大于size字節(jié),則把該消息截斷,截斷部分將被丟棄,且不通知發(fā)送進程。
如果成功則返回0,如果失敗則返回-1,并且錯誤原因存于error中。
錯誤代碼:
·?EAGAIN:參數(shù)msgflg設為IPC_NOWAIT,而消息隊列已滿。
·?EIDRM:標識符為msqid的消息隊列已被刪除。
·?EACCESS:無權限寫入消息隊列。
·?EFAULT:參數(shù)msgp指向無效的內存地址。
·?EINTR:隊列已滿而處于等待情況下被信號中斷。
·?EINVAL:無效的參數(shù)msqid、msgsz或參數(shù)消息類型type小于0。
msgsnd()為阻塞函數(shù),當消息隊列容量滿或消息個數(shù)滿會阻塞。消息隊列已被刪除,則返回EIDRM錯誤;被信號中斷返回E_INTR錯誤。
如果設置IPC_NOWAIT消息隊列滿或個數(shù)滿時會返回-1,并且置EAGAIN錯誤。
msgsnd()解除阻塞的條件有以下三個條件:
1.?消息隊列中有容納該消息的空間。
2.?msqid代表的消息隊列被刪除。
3.?調用msgsnd函數(shù)的進程被信號中斷。
msgrcv()函數(shù)
函數(shù)原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
msgrcv()函數(shù)是從標識符為msqid的消息隊列讀取消息并將消息存儲到msgp中,讀取后把此消息從消息隊列中刪除,也就是俗話說的接收消息。
函數(shù)傳入值:
·?msqid:消息隊列標識符。
·?msgp:存放消息的結構體,結構體類型要與msgsnd()函數(shù)發(fā)送的類型相同。
·?msgsz:要接收消息的大小,不包含消息類型占用的4個字節(jié)。
·?msgtyp有多個可選的值:如果為0則表示接收第一個消息,如果大于0則表示接收類型等于msgtyp的第一個消息,而如果小于0則表示接收類型等于或者小于msgtyp絕對值的第一個消息。
msgflg取值情況如下:
·?0: 阻塞式接收消息,沒有該類型的消息msgrcv函數(shù)一直阻塞等待
·?IPC_NOWAIT:若在消息隊列中并沒有相應類型的消息可以接收,則函數(shù)立即返回,此時錯誤碼為ENOMSG
·?IPC_EXCEPT:與msgtype配合使用返回隊列中第一個類型不為msgtype的消息
·?IPC_NOERROR:如果隊列中滿足條件的消息內容大于所請求的size字節(jié),則把該消息截斷,截斷部分將被丟棄
msgrcv()函數(shù)如果接收消息成功則返回實際讀取到的消息數(shù)據(jù)長度,否則返回-1,錯誤原因存于error中。
錯誤代碼
·?E2BIG:消息數(shù)據(jù)長度大于msgsz而msgflag沒有設置IPC_NOERROR
·?EIDRM:標識符為msqid的消息隊列已被刪除
·?EACCESS:無權限讀取該消息隊列
·?EFAULT:參數(shù)msgp指向無效的內存地址
·?ENOMSG:參數(shù)msgflg設為IPC_NOWAIT,而消息隊列中無消息可讀
·?EINTR:等待讀取隊列內的消息情況下被信號中斷
msgrcv()函數(shù)解除阻塞的條件也有三個:
1.?消息隊列中有了滿足條件的消息。
2.?msqid代表的消息隊列被刪除。
3.?調用msgrcv()函數(shù)的進程被信號中斷。
操作消息隊列
消息隊列是可以被用戶操作的,比如設置或者獲取消息隊列的相關屬性,那么可以通過msgctl()函數(shù)去處理它。
函數(shù)原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函數(shù)傳入值:
·?msqid:消息隊列標識符。
cmd的取值有多個:
·?IPC_STAT 獲取該 MSG 的信息,獲取到的信息會儲存在結構體 msqid_ds 類型的buf中。
·?IPC_SET 設置消息隊列的屬性,要設置的屬性需先存儲在結構體 msqid_ds類型的buf中,可設置的屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,儲存在結構體 msqid_ds。
·?IPC_RMID 立即刪除該 MSG,并且喚醒所有阻塞在該 MSG 上的進程,同時忽略第三個參數(shù)。
·?IPC_INFO 獲得關于當前系統(tǒng)中 MSG 的限制值信息。
·?MSG_INFO 獲得關于當前系統(tǒng)中 MSG 的相關資源消耗信息。
·?MSG_STAT 同 IPC_STAT,但 msgid 為該消息隊列在內核中記錄所有消息隊列信息的數(shù)組的下標,因此通過迭代所有的下標可以獲得系統(tǒng)中所有消息隊列的相關信息。
·?buf:相關信息結構體緩沖區(qū)。
函數(shù)返回值:
·?成功:0
·?出錯:-1,錯誤原因存于error中
錯誤代碼:
·?EACCESS:參數(shù)cmd為IPC_STAT,卻無權限讀取該消息隊列。
·?EFAULT:參數(shù)buf指向無效的內存地址。
·?EIDRM:標識符為msqid的消息隊列已被刪除。
·?EINVAL:無效的參數(shù)cmd或msqid。
·?EPERM:參數(shù)cmd為IPC_SET或IPC_RMID,卻無足夠的權限執(zhí)行。
消息隊列實例
發(fā)送者:
l?獲取消息隊列的 ID
l?將數(shù)據(jù)放入一個附帶有標識的特殊的結構體,發(fā)送給消息隊列。
接收者:
l?獲取消息隊列的 ID
l?將指定標識的消息讀出。
l?當發(fā)送者和接收者都不再使用消息隊列時,及時刪除它以釋放系統(tǒng)資源。
發(fā)送函數(shù):
接收函數(shù)
第一個終端執(zhí)行 msgsnd 發(fā)送消息
第二個終端執(zhí)行 msgrcv 接收消息
Hankin
2020.08.17
總結
以上是生活随笔為你收集整理的jmstemplate 获取队列id_学习Linux(38)消息队列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python zen_Python的宗旨
- 下一篇: 电脑安全注意事项_松下洗衣机维修方法及注