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