linux c程式設計:Posix訊息佇列
Posix訊息佇列可以認為是一個訊息連結串列. 有足夠寫許可權的執行緒可以往佇列中放置訊息, 有足夠讀許可權的執行緒可以從佇列中取走訊息
在某個程序往一個佇列寫入訊息前, 並不需要另外某個程序在該佇列上等待訊息的到達.
這跟管道和FIFO是相反的, 因為對於管道,FIFO來說, 除非讀出者已經存在, 光有寫入者是沒有意義的。一個程序在往某訊息佇列寫入訊息後, 終止程序. 另一個程序某時刻讀出該訊息;然而對於管帶或FIFO而言, 當管道或FIFO的最後一次關閉發生時,仍在管道或FIFO中的資料將被拋棄
訊息佇列的佈局如下圖
下面介紹佇列用到函式:
1 mqd_t mq_open(const char* name, int oflag, mode_t mode, struct mq_attr* attr);
函式開啟或者建立一個posix訊息佇列。當我們的實際操作是建立一個新的佇列時(即所要建立的佇列不存在, 且oflag中已經指定O_CREAT), mode 和 attr引數是需要的.
函式的返回值稱為訊息佇列描述符,
如果沒有連結的話,會出現下面的錯誤
[email protected]:/home/zhf/codeblocks_prj/unix_network# gcc -c main.c -o main_tmp
[email protected]:/home/zhf/codeblocks_prj/unix_network# ./main_tmp test2
bash: ./main_tmp: 無法執行二進位制檔案: 可執行檔案格式錯誤
name:
posix IPC名字。(必須以/開頭,且後面不能再含有/)
oflag:
標誌。
標誌——————————作用
O_CREAT———————沒有該物件則建立
O_EXCL————————如果O_CREAT指定,但name不存在,就返回錯誤
O_NONBLOCK—————以非阻塞方式開啟訊息佇列
O_RDONLY———————只讀
O_RDWR————————讀寫
O_WRONLY———————只寫
mode:
許可權——————作用
S_IWUSR——使用者/屬主寫
S_IRUSR——使用者/屬主讀
S_IWGRP——組成員寫
S_IRGRP——組成員讀
S_IWOTH——其他使用者寫
S_IROTH——其他使用者讀
attr:結構體如下:
struct mq_attr {
long mq_flags; /* Flags: 0 or O_NONBLOCK */
————在mq_open建立時被初始化;
————在mq_setattr中設定;
————其值為0(阻塞)或者O_NONBLOCK(非阻塞)。
long mq_maxmsg; /* Max. # of messages on queue */
——佇列的訊息個數最大值:
————只能在mq_open建立時被初始化。
long mq_msgsize; /* Max. message size (bytes) */
——佇列中每個訊息的最大值:
————只能在mq_open建立時被初始化。
long mq_curmsgs; /* # of messages currently in queue */
——當前佇列的訊息個數:
————在mq_getattr中獲得。
};
2 int mq_close(mqd_t mqdes):關閉訊息佇列
關閉之後呼叫程序不在使用該描述符,但訊息佇列不會從系統中刪除,程序終止時,會自動關閉已開啟的訊息佇列,和呼叫mq_close一樣。引數為mq_open()函式返回的值
3 int mq_unlink(const char *name): 從系統中刪除某個訊息佇列
刪除會馬上發生,即使該佇列的描述符引用計數仍然大於0。引數為mq_open()函式第一個引數。
4設定和獲取佇列屬性
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);
引數mqdes為mq_open()函式返回的訊息佇列描述符。
引數attr、newattr、oldattr為訊息佇列屬性結構體指標;
5向訊息佇列放置和取走訊息
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
引數msg_ptr為指向訊息的指標。
msg_len為訊息長度,該值不能大於屬性值中mq_msgsize的值。
msg_prio為優先順序,訊息在佇列中將按照優先順序大小順序來排列訊息。
如果訊息佇列已滿,mq_send()函式將阻塞,直到佇列有可用空間再次允許放置訊息或該呼叫被訊號打斷;如果O_NONBLOCK被指定,mq_send()那麼將不會阻塞,而是返回EAGAIN錯誤。如果佇列空,mq_receive()函式將阻塞,直到訊息佇列中有新的訊息;如果O_NONBLOCK被指定,mq_receive()那麼將不會阻塞,而是返回EAGAIN錯誤。
下面就來看第一個例子:
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <mqueue.h>
#include <fcntl.h>
#include "func.h"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(int argc,char **argv)
{
int c,flags;
mqd_t mqd;
struct mq_attr attr;
flags = O_RDWR|O_CREAT;
printf("create mqueue.\n");
if((mqd = mq_open(argv[1],flags,FILE_MODE,NULL)) == -1)
{
perror("mq_open() error");
exit(-1);
}
mq_getattr(mqd,&attr);
printf("max #msgs = %ld,max #bytes/msg = %ld,#currently on queue = %ld\n",attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
mq_close(mqd);
exit(0);
}
在執行程式碼前,首先要建立訊息佇列存放的路徑。一般是/dev/mqueue。沒有的話需要建立一個。然後執行mount -t mqueue none /dev/mqueue進行掛載。參考說明如下
gcc main.c -o main_tmp -lrt
./main_tmp /test123
執行完後,在dev/mqueue路徑下面就能看到建立的佇列檔案以及佇列裡面的資訊。
cat /dev/mqueue/test123
QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0