1. 程式人生 > >linux c程式設計:Posix訊息佇列

linux c程式設計:Posix訊息佇列

 Posix訊息佇列可以認為是一個訊息連結串列有足夠寫許可權的執行緒可以往佇列中放置訊息有足夠讀許可權的執行緒可以從佇列中取走訊息

在某個程序往一個佇列寫入訊息前並不需要另外某個程序在該佇列上等待訊息的到達.

這跟管道和FIFO是相反的因為對於管道,FIFO來說除非讀出者已經存在光有寫入者是沒有意義的。一個程序在往某訊息佇列寫入訊息後終止程序另一個程序某時刻讀出該訊息;然而對於管帶或FIFO而言當管道或FIFO的最後一次關閉發生時,仍在管道或FIFO中的資料將被拋棄

訊息佇列的佈局如下圖

下面介紹佇列用到函式:

1 mqd_t  mq_openconst char* name, int oflag, mode_t mode, struct mq_attr* attr);

函式開啟或者建立一個posix訊息佇列。當我們的實際操作是建立一個新的佇列時(即所要建立的佇列不存在oflag中已經指定O_CREAT), mode 和 attr引數是需要的.
函式的返回值稱為訊息佇列描述符

這個值用作其他訊息佇列操作函式的第一個引數值。另外根據man 7 mq_overview裡面的介紹。在連結的時候必須連結librt庫,採用-lrt的方法

如果沒有連結的話,會出現下面的錯誤

[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);   

引數mqdesmq_open()函式返回的訊息佇列描述符。

引數attrnewattroldattr為訊息佇列屬性結構體指標;

 

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