POSIX訊息佇列
訊息佇列可以認為是一個連結串列。程式(執行緒)可以往裡寫訊息,也可以從裡面取出訊息。一個程式可以往某個訊息佇列裡寫訊息,然後終止,另一個程式隨時可以從訊息佇列裡取走這些訊息。這裡也說明了,訊息佇列具有隨核心的持續性,也就是系統不重啟,訊息佇列永久存在。
3.2.1 建立(並開啟)、關閉、刪除一個訊息佇列
/* For O_* constants */ /* For mode constants */ mqd_t mq_open(const char *name, int oflag); mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr); /* 函式說明:函式建立或開啟一個訊息佇列,建立後,在/dev/mqueque下可以看到對應檔案 返回值:成功返回訊息佇列描述符,失敗返回-1,錯誤原因存於errno中 name: 檔案路徑,必須以/開頭,而且有且只有一個/ oflag: 與open的開啟標誌一樣,加上O_CREAT標誌,能夠建立訊息佇列 mode: 與open的開啟mode一樣 attr: 建立訊息佇列的時候需要,指定訊息佇列大小訊息個數等,為NULL表示使用預設引數 */ /*訊息佇列屬性結構體*/ struct mq_attr { long mq_flags; /* Flags: 0 or O_NONBLOCK */ long mq_maxmsg; /* Max. # of messages on queue */ long mq_msgsize; /* Max. message size (bytes) */ long mq_curmsgs; /* # of messages currently in queue */ }; mqd_t mq_close(mqd_t mqdes); /* 函式說明:關閉一個開啟的訊息佇列,表示本程式不再對該訊息佇列讀寫 返回值:成功返回0,失敗返回-1,錯誤原因存於errno中 */ int mq_unlink(const char *name); /* 函式說明:刪除一個訊息佇列,好比刪除一個檔案,其他程式再也無法訪問 返回值:成功返回0,失敗返回-1,錯誤原因存於errno中 */
需要注意:
訊息佇列的名字最好使用“/”打頭,並且只有一個“/”的名字。否則可能出現移植性問題;它必須符合已有的路徑名規則(最多由PATH_MAX個位元組構成,包括結尾的空位元組)。
3.2.2 Posix訊息佇列讀寫
訊息佇列的讀寫主要使用下面兩個函式:
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); /* 功能:傳送一條訊息到佇列 mqdes:訊息佇列檔案描述符 msg_ptr: 訊息內容 msg_len: 內容長度 msg_prio: 訊息優先順序,它是一個小於MQ_PRIO_MAX的數, 數值越大,優先順序越高 返回:若成功則為訊息中位元組數,若出錯則為-1 */ ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); /* 功能:從佇列接收一條訊息 mqdes:訊息佇列檔案描述符 msg_ptr: 訊息內容 msg_len: 內容長度 msg_prio: 訊息優先順序 返回:若成功則為0, 若出錯則為-1 */
原始碼sendmq.c
void error_print(const char* msg) { perror(msg); exit(-1); } /*向訊息佇列傳送訊息,訊息佇列名及傳送的資訊通過引數傳遞*/ int main(int argc, char *argv[]) { const char* mqname = "/mymq"; char buf[] = "helloworld"; mqd_t mqd; int ret; //只寫模式找開訊息佇列,不存在就建立 mqd = mq_open(mqname, O_WRONLY | O_CREAT, 0666, NULL); if(mqd < 0) error_print("mq_open"); /*向訊息佇列寫入訊息,如訊息佇列滿則阻塞,直到訊息佇列有空閒時再寫入*/ ret = mq_send(mqd, buf, strlen(buf) + 1, 10); if(ret < 0) error_print("mq_send"); ret = mq_close(mqd); if(ret < 0) error_print("mq_close"); return 0; }
編譯:
gcc -o sendmq sendmq.c -lrt
執行後可以在/dev/mqueue下看到mymq檔案。
原始碼recvmq.c
void error_print(const char* msg) { perror(msg); exit(-1); } /*讀取某訊息佇列,訊息佇列名通過引數傳遞*/ int main(int argc, char *argv[]) { const char* mqname = "/mymq"; mqd_t mqd; struct mq_attr attr; char *buf; unsigned int prio; int ret; /*只讀模式開啟訊息佇列*/ mqd = mq_open(mqname, O_RDONLY); if(mqd < 0) error_print("mq_open"); /*取得訊息佇列屬性,根據mq_msgsize動態申請記憶體*/ ret = mq_getattr(mqd, &attr); if(ret < 0) error_print("mq_getattr"); /*動態申請保證能存放單條訊息的記憶體*/ buf = (char*)malloc(attr.mq_msgsize); if(NULL == buf) error_print("malloc"); /*接收一條訊息*/ ret = mq_receive(mqd, buf, attr.mq_msgsize, &prio); if(ret < 0) error_print("receive"); printf("read data %s priority %u\n", buf, prio); ret = mq_close(mqd); if(ret < 0) error_print("mq_close"); /*訊息佇列使用完後就可以刪除 ret = mq_unlink(mqname); if(ret < 0) error_print("mq_unlink"); */ free(buf); return 0; }
編譯並執行:
gcc -o recvmq recvmq.c -lrt
需要注意的是:當訊息不斷髮送,達到訊息佇列容量最大值的時候,mq_send將阻塞,知道訊息佇列被接收走,如果訊息還未接收,就把訊息佇列檔案刪除,則訊息丟失。
3.2.3 訊息佇列的屬性
Posix訊息佇列的屬性使用如下結構存放: struct mq_attr { long mq_flags; /*阻塞標誌位,0為非阻塞(O_NONBLOCK)*/ long mq_maxmsg; /*佇列所允許的最大訊息條數*/ long mq_msgsize; /*每條訊息的最大位元組數*/ long mq_curmsgs; /*佇列當前的訊息條數*/ }; /* 佇列可以在建立時由mq_open()函式的第四個引數指定mq_maxmsg,mq_msgsize。 如建立時沒有指定則使用預設值,一旦建立,則不可再改變。 佇列可以在建立後由mq_setattr()函式設定mq_flags */ /*取得訊息佇列屬性,放到mqstat中*/ int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); /*設定訊息佇列屬性,設定值由mqstat提供,原先值寫入omqstat中,只是用來改變O_NONBLOCK標誌*/ int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat); 均返回:若成功則為0,若出錯為-1
獲取訊息佇列的屬性:
attrmq.c
void error_print(const char* msg) { perror(msg); exit(-1); } int main() { mqd_t mqd; int ret; struct mq_attr mqattr; const char* mqname = "/mymq"; /*只讀模式開啟訊息佇列*/ mqd = mq_open(mqname, O_CREAT | O_RDONLY, 0666, NULL); if(mqd < 0) error_print("mq_open"); /*取得訊息佇列屬性*/ ret = mq_getattr(mqd, &attr); if(ret < 0) error_print("mq_getattr"); printf("nonblock flag:%ld\n", attr.mq_flags); printf("max msgs:%ld\n", attr.mq_maxmsg); printf("max msg size:%ld\n", attr.mq_msgsize); printf("current msg count:%ld\n", attr.mq_curmsgs); ret = mq_close(mqd); if(ret < 0) error_print("mq_close"); ret = mq_unlink(mqname); if(ret < 0) error_print("mq_unlink"); return 0; }
編譯並執行:
gcc -o attrmq attrmq.c -lrt
設定訊息佇列的屬性:
原始碼setarrtmq.c
void error_print(const char* msg) { perror(msg); exit(-1); } int main() { mqd_t mqd; int ret; const char * mqname = "/mymq"; struct mq_attr mqattr; mqattr.mq_maxmsg = 10; mqattr.mq_msgsize = 8192; mqd = mq_open(mqname, O_RDWR | O_CREAT, 0666, &mqattr); if(mqd < 0) { perror("mq_open"); exit(1); } mqattr.mq_flags = O_NONBLOCK; mq_setattr(mqd, &mqattr, NULL);// mq_setattr()只關注mq_flags /*取得訊息佇列屬性*/ ret = mq_getattr(mqd, &mqattr); if(ret < 0) error_print("mq_getattr"); printf("nonblock flag:%ld\n", mqattr.mq_flags); printf("max msgs:%ld\n", mqattr.mq_maxmsg); printf("max msg size:%ld\n", mqattr.mq_msgsize); printf("current msg count:%ld\n", mqattr.mq_curmsgs); ret = mq_close(mqd); if(ret < 0) error_print("mq_close"); return 0; }
編譯執行:
gcc -o setattrmq setattrmq.c -lrt
訊息佇列系統限制檢視:
cat /proc/sys/fs/mqueue/msg_max #檢視訊息佇列的訊息最大長度 cat /proc/sys/fs/mqueue/msgsize_max #檢視訊息佇列的訊息最大個數
相關文章
- 訊息佇列系列一:訊息佇列應用佇列
- 訊息佇列佇列
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型
- kafka 訊息佇列Kafka佇列
- 訊息佇列(MQ)佇列MQ
- [Redis]訊息佇列Redis佇列
- [訊息佇列]rocketMQ佇列MQ
- [訊息佇列]RabbitMQ佇列MQ
- Kafka訊息佇列Kafka佇列
- RabbitMQ訊息佇列MQ佇列
- 全面理解Handler-1:理解訊息佇列,手寫訊息佇列佇列
- rabbitmq訊息佇列原理MQ佇列
- 訊息佇列之 RocketMQ佇列MQ
- 訊息佇列二三事佇列
- MQ訊息佇列_RabbitMQMQ佇列
- 訊息佇列設計佇列
- 訊息佇列深入解析佇列
- 訊息佇列之 ActiveMQ佇列MQ
- 訊息佇列之RocketMQ佇列MQ
- 訊息佇列雜談佇列
- 訊息佇列之RabbitMQ佇列MQ
- 訊息佇列簡史佇列
- RabbitMQ訊息佇列(五):Routing 訊息路由MQ佇列路由
- 程式間通訊--訊息佇列佇列
- 訊息機制篇——初識訊息與訊息佇列佇列
- 什麼是訊息佇列?佇列
- 訊息佇列mq總結佇列MQ
- Python使用RocketMQ(訊息佇列)PythonMQ佇列
- SpringBoot:初探 RabbitMQ 訊息佇列Spring BootMQ佇列
- 使用Redis做訊息佇列Redis佇列
- PHP Kafka 訊息佇列使用PHPKafka佇列
- 知識分享--訊息佇列佇列
- 「訊息佇列」看過來!佇列
- [Redis]延遲訊息佇列Redis佇列
- 訊息佇列 大雜燴佇列
- 訊息佇列中的Oracle佇列Oracle
- Java面試—訊息佇列Java面試佇列
- 訊息佇列之概論佇列
- Redis實現訊息佇列Redis佇列