Linux进程间通信二 System V 消息队列简介与示例
1. SystemV消息隊(duì)列簡(jiǎn)介
消息隊(duì)列,顧名思義即是存放消息的隊(duì)列,內(nèi)核為每個(gè)SystemV 維護(hù)了一個(gè)msg_queue的結(jié)構(gòu)體,里面記錄了每個(gè)消息隊(duì)列的信息。
struct msg_queue {structkern_ipc_perm q_perm; // 權(quán)限相關(guān)time_tq_stime; /* 上一次 msgsnd時(shí)間 */time_tq_rtime; /* 上一次 msgrcv時(shí)間 */time_tq_ctime; /* 屬性變化時(shí)間 */unsignedlong q_cbytes; /* 隊(duì)列當(dāng)前字節(jié)總數(shù) */unsignedlong q_qnum; /* 隊(duì)列當(dāng)前消息總數(shù) */unsignedlong q_qbytes; /* 一個(gè)消息隊(duì)列允許最大字節(jié)數(shù) */pid_tq_lspid; /* 上一個(gè)調(diào)用msgsnd的進(jìn)程ID */pid_tq_lrpid; /* 上一個(gè)調(diào)用msgrcv的進(jìn)程ID */structlist_head q_messages;structlist_head q_receivers;structlist_head q_senders; };消息隊(duì)列存儲(chǔ)消息的結(jié)構(gòu)體需要用戶自定義,且第一個(gè)字段必須是long類型。雖然誕生已久,但是systemV支持優(yōu)先級(jí)隊(duì)列和FIFO這一點(diǎn)確實(shí)是挺強(qiáng)大的,缺點(diǎn)也很明顯,不支持IO多路復(fù)用。一般大型的MQ開發(fā)很少用到SystemV mq,因?yàn)榇嬖诤芏嘞拗?#xff0c;比如系統(tǒng)能夠創(chuàng)建的消息隊(duì)列個(gè)數(shù)有限,單條消息大小受限,單個(gè)消息隊(duì)列里面消息個(gè)數(shù)受限等等。即便如此還是需要學(xué)習(xí)一下systemV消息隊(duì)列,以后自己做相關(guān)的開發(fā)可以借鑒相關(guān)的設(shè)計(jì)思路。
?
2. API接口
2. 1 創(chuàng)建或獲取消息隊(duì)列ID
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h>/** * @brief 創(chuàng)建或獲取消息隊(duì)列ID * * @params key 標(biāo)識(shí)符,整形變量,三種方式,固定值,IPC_PRIVATE,ftok生成 * @params msgflg,標(biāo)志位,IPC_CREAT and IPC_EXCL * * @returns 成功返回消息隊(duì)列ID,失敗返回-1 */int msgget(key_t key, int msgflg);2.2 寫消息
/** * @brief 發(fā)送消息 * * @params msqid 消息隊(duì)列ID * @params msgp 待發(fā)送消息的地址,類型需要自定義且第一個(gè)元素為long類型 * @params msgsz 消息大小 * @params msgflg 標(biāo)志位,IPC_NOWAIT,未指定情況下,如果消息隊(duì)列空間滿,默認(rèn)阻塞,設(shè)置此標(biāo)志位則立即返回。* @returns 成功返回消息隊(duì)列ID,失敗返回-1 */int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);2.3 讀消息
/** * @brief 發(fā)送消息 * * @params msqid 消息隊(duì)列ID * @params msgp 接收消息的緩存,需要和發(fā)送方約定好結(jié)構(gòu)體 * @params msgsz 接收消息最大長(zhǎng)度,不包括消息類型字段 * @params msgtyp 要接收的消息類型。 >0分為兩種情況,如果設(shè)置了MSG_EXCEPT,從消息隊(duì)列中取出第一條消息類型相同的消息。 否則,取出第一條消息類型不同的消息。 =0相當(dāng)于先入先出,最早進(jìn)入消息隊(duì)列的消息被取出。 <0相當(dāng)于優(yōu)先級(jí)隊(duì)列,取出值小于或等于msgtyp絕對(duì)值的第一條消息* @params msgflg 標(biāo)志位,IPC_NOWAIT,MSG_EXCEPT,MSG_NOERROR(消息過長(zhǎng)時(shí)是否截?cái)?* @returns 成功返回接收到的消息內(nèi)容長(zhǎng)度,失敗返回-1 */ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);2.4 消息隊(duì)列其它控制操作
/** * @brief 控制操作 * * @params msqid 消息隊(duì)列ID * @params cmd 控制命令類型 IPC_STAT 獲取或設(shè)置消息隊(duì)列的屬性 IPC_SET 設(shè)置權(quán)限相關(guān)屬性 IPC_RMID 刪除消息隊(duì)列,釋放消息隊(duì)列中的所有消息* @returns 成功返回0,失敗返回-1 */int msgctl(int msqid, int cmd, struct msqid_ds *buf);3. 示例
下面是一個(gè)簡(jiǎn)單的消息隊(duì)列例子,分為讀消息和寫消息兩個(gè)部分。
3.1讀取
// 讀取消息隊(duì)列#include <stdio.h> #include <sys/types.h> #include <sys/msg.h> #include <sys/ipc.h> #include <string.h>// 消息結(jié)構(gòu)體,第一個(gè)元素必須是消息類型 struct msg{long mtype; // 消息類型char data[1024]; // 數(shù)據(jù) };int main() {int mq_id = 0;key_t key = 1357; // 標(biāo)識(shí)符,三種方式,固定值,IPC_PRIVATE,ftok生成ssize_t msg_size;struct msg message={0};// 創(chuàng)建或獲取消息隊(duì)列mq_id = msgget(key, IPC_CREAT);if (mq_id == -1){printf("create mq error");return mq_id;}// 循環(huán)監(jiān)聽消息隊(duì)列while (1){// 阻塞監(jiān)聽所有消息類型的消息msg_size = msgrcv(mq_id, (void *)&message, sizeof(message), 0, 0); if (msg_size != -1){printf("read msg type:%ld, data:%s\n", message.mtype, message.data);}memset(&message,0,sizeof(message));}return 0; }3.2 寫入
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdlib.h> #include <string.h>// 消息結(jié)構(gòu)體,第一個(gè)元素必須是消息類型 struct msg{long mtype; // 消息類型char data[1024]; // 數(shù)據(jù) };int main(int argc, char** argv) {if (argc < 3){printf("invalid param, please input msg type and data\n");printf("Usage: ./mq_write type data\n");return -1;}int mq_id = 0;key_t key = 1357; // 標(biāo)識(shí)符,三種方式,固定值,IPC_PRIVATE,ftok生成// 創(chuàng)建或獲取消息隊(duì)列mq_id = msgget(key, IPC_CREAT);if (mq_id == -1){printf("create mq error\n");return mq_id;}struct msg message;message.mtype = strtol(argv[1],NULL,0);strcpy(message.data, argv[2]);// 發(fā)送消息if (msgsnd(mq_id, (const void*)&message, sizeof(message), 0) == 0){printf("send message succ\n");}else{printf("send message error\n");}return 0; }3.3 編譯&運(yùn)行
gcc -o mq_read mq_read.c gcc -o mq_wirte mq_write.c?
4. 注意事項(xiàng)
4.1??消息隊(duì)列限制
MSGMAX 單條消息大小有限 cat /proc/sys/kernel/msgmaxMSGMNI 消息隊(duì)列總個(gè)數(shù)有限 cat /proc/sys/kernel/msgmniMSGMNB 單個(gè)消息隊(duì)列最大大小 cat /proc/sys/kernel/msgmnb5. 參考資料
1.?https://man7.org/linux/man-pages/man2/msgsnd.2.html
2. 《Linux環(huán)境編程 從應(yīng)用到內(nèi)核》
3. 《Unix網(wǎng)絡(luò)編程 卷二 進(jìn)程間通信》
================================================================================================
Linux應(yīng)用程序、內(nèi)核、驅(qū)動(dòng)、后臺(tái)開發(fā)交流討論群(745510310),感興趣的同學(xué)可以加群討論、交流、資料查找等,前進(jìn)的道路上,你不是一個(gè)人奧^_^。...
總結(jié)
以上是生活随笔為你收集整理的Linux进程间通信二 System V 消息队列简介与示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux进程间通信一 System V
- 下一篇: Linux进程间通信三 System V