<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    消息隊列接口API(posix 接口和 system v接口)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接 消息隊列 posix API

    消息隊列(也叫做報文隊列)能夠克服早期unix通信機制的一些缺點。信號這種通信方式更像\"即時\"的通信方式,它要求接受信號的進程在某個時間范圍內對信號做出反應,因此該信號最多在接受信號進程的生命周期內才有意義,信號所傳遞的信息是接近于隨進程持續的概念(process-persistent);管道及有名管道則是典型的隨進程持續IPC,并且,只能傳送無格式的字節流無疑會給應用程序開發帶來不便,另外,它的緩沖區大小也受到限制消息隊列就是一個消息的鏈表。可以把消息看作一個記錄,具有特定的格式以及特定的優先級。對消息隊列有寫權限的進程可以向中按照一定的規則添加新消息;對消息隊列有讀權限的進程則可以從消息隊列中讀走消息。消息隊列是隨內核持續的。

    mq_open - 打開一個消息隊列

    概要

    #include <fcntl.h> /* 定義 了O_* 常量 */

    #include <sys/stat.h> /* 定義了 mode 常量 */

     #include <mqueue.h>

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

    需要 -lrt 來鏈接。

    描述

    mq_open() 創建一個新的 POSIX 消息隊列或打開一個存在的隊列。這個隊列使用 name 標識。每個消息隊列都通過形如/somename 的名字來區分,這是一個包含起始斜杠在內的最大長度不超過 NAME_MAX(如 225)的以空字符結尾的字符串,在起始斜杠之后不允許再有斜杠。

    參數 oflag 參數指定控制操作的標志。(這個標志的值可以通過包含 <fcntl.h> 來獲得。)下面給出的標志至少需要指定一個:

    O_RDONLY 以只能收取消息的方式打開隊列。 O_WRONLY 以只能發送消息的方式打開的隊列。 O_RDWR 以可發送也可收取消息的方式打開隊列。

    零個或多個下面列出的標志可以用 位或 到 oflag 里:

    O_NONBLOCK 以非阻塞的方式打開隊列。具體情況是在 mq_receive(3) 和 mq_send(3) 要阻塞的時候,這些函數使用錯誤 EAGAIN來替代。 O_CREAT 如果不存在則創建消息隊列。消息隊列的所有者(用戶 ID)被設置為調用進程的有效用名 ID。組屬性(組 ID)被設置為調用進程的有效組 ID。 O_EXCL 如果 O_CREAT 在 oflag 里指定,當名為 name 隊列已經存在時,讓函數以 EEXIST 失敗。

    如果 O_CREAT 在 oflag 里指定,那么兩個額外的參數也必須給定。mode 參數指定新隊列的權限,這與 open(2) 一樣。(描述權限的符號常量可以通過包含 <sys/stat.h> 來獲得。)權限設置會被進程掩碼處理。參數 attr 指定隊列的屬性。參考 mq_getattr(3) 來了解細節。如果 attr 是 NULL,隊列將使用實現定義的默認屬性來創建。

    返回值

    成功時,mq_open() 返回一個能被其它消息隊列函數使用的消息隊列描述符。失敗時,mq_open() 返回 (mqd_t) -1,并設置errno 來指明錯誤。

    錯誤 EACCES 隊列存在,但是調用者沒有權限以指定的方式打開。 EACCES name 包含多個斜杠。 EEXIST 在 oflag 里同時指定了O_CREAT 和 O_EXCL,但是名字 name 的隊列已經存在。 EINVAL O_CREAT 在 oflag 里存在,并且 attr 不是 NULL,但是 attr->mq_maxmsg 或 attr->mq_msqsize 是無效的。這兩個域都必須大于零。對于一個非特權(沒有 CAP_SYS_RESOURCE 能力)進程attr->mq_maxmsg 必須小于或等于 msg_max 限制,并且 attr->mq_msgsize 也必須小于或等于 msgsize_max 限制。此外,就算是特權進程,attr->mq_maxmsg 也不能超過 HARD_MAX 限制。(參看 mq_overview(7) 了解限制的更多細節。) EMFILE 進程已經達到打開的文件和消息隊列的最大數目。 ENAMETOOLONG name 太長了。 ENFILE 達到系統允許打開文件個數和消息隊列的全局上限。 ENOENT O_CREAT 沒有在 oflag 里指定,并且沒有名字 name 的隊列存在。 ENOENT name 只是 "/" 而沒有其它字符。 ENOMEM 內存不足。 ENOSPC 沒有足夠的內存來創建新的消息隊列。這個可能是因為達到 queues_max 限制而引起的,參考 mq_overview(7)。

    mq_close - 關閉一個消息隊列描述符

    概要#include <mqueue.h> int mq_close(mqd_t mqdes);

    需要 -lrt 來鏈接。

    描述

    mq_close() 關閉消息隊列描述符 mqdes

    如果調用進程在消息隊列 mqdes 綁定了通知請求,那么這個請求被刪除,此后其它進程就可以綁定通知請求到此消息隊列。

    返回值

    成功時,mq_close() 返回 0;錯誤時,返回 -1,并把 errno 設置為合適的值。

    錯誤 EBADF mqdes 指定的描述符無效。

     

    mq_getattr, mq_setattr - 取得/設置消息隊列屬性 概要 #include <mqueue.h> int mq_getattr(mqd_t mqdes, struct mq_attr *attr);  int mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);

    需要 -lrt 來鏈接。

    描述mq_getattr() 和 mq_setattr() 取得和更改 mqdes 引用的消息隊列的屬性。

    mq_getattr() 在 attr 指向的內存里返回一個 mq_attr 結構體。這個結構定義為:

    struct mq_attr { long mq_flags; /* 標志:0 或 O_NONBLOCK */ long mq_maxmsg; /* 隊列中消息個數最大值 */ long mq_msgsize; /* 消息大小最大值 */ long mq_curmsgs; /* 隊列中當前消息個數 */ };

    mq_flags 的域包含打開消息隊列描述符相關的標志。這個標志由 mq_open(3) 初始化。能存在于這個標志的域只有 O_NONBLOCK

    mq_maxmsg 和 mq_msgsize 兩個域由 mq_open(3) 在隊列創建時設置的。mq_maxmsg 是使用 mq_sen(3) 發送數據大小的上限。mq_msgsize 是當前隊列可以緩存消息個數的上限。用于設置這些域的軟上限的兩個 /proc 文件在 mq_open(3) 中有描述。

    mq_curmsgs 域用于返回當前隊列里已經有消息個數。

    mq_setattr() 設置消息隊列的屬性,設置時使用由 newattr 指針指向的 mq_attr 結構的信息。屬性中只有標志 mq_flasgs 里的O_NONBLOCK 標志可以更改,其它在 newattr 內的域都被忽略。如果 oldattr 不是空指針,那么它指向的內存用于返回現有的屬性結構mq_attr,此時包含信息與通過 mq_getattr() 取得的信息相同。

    返回值成功時 mq_getattr() 和 mq_setattr() 返回 0;錯誤時,-1 被返回,并同時設置 errno 值來指明錯誤。 錯誤 EBADF mqdes 指定的描述符無效。 EINVAL newattr->mq_flags 包含除 O_NONBLOCK 之外的位。   mq_notify - 注冊一個當消息到達時的通知 概要 #include <mqueue.h> int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

    需要 -lrt 來鏈接。

    描述mq_notify() 允許調用進程針對 mqdes 引用的空隊列注冊或注銷新消息異步通知的遞送。

    sevp 參數是一個指向 sigevent 結構的指針。關于這個結構的定義與相關細節,見 sigevent(7)。

    如果 sevp 是一個非空指針,那么 mq_notify() 注冊調用進程以在消息到達時收到通知。sevp 指向的 sigevent 結構中的 sigev_notify域用于指明通知的方式。這個域可以有如下幾個值:

    SIGEV_NONE 一個“空”通知:調用進程作為通知的目標被注冊,但是當消息達到時,沒有通知被遞送。 SIGEV_SIGNAL 通過發送在sigev_signo 指定的信號來通知進程。見 sigevent(7) 中的細節描述。siginfo_t 結構中的 si_code 域將被設置為 SI_MESGQ。進一步說,si_pid 將被設置為發送消息的進程的進程 ID,同時 si_uid 將被設置為發送進程的真實用戶 ID。 SIGEV_THREAD 當消息到達時,啟動一個新線程來調用 sigev_notify_function。參見 sigevent(7) 來了解其中細節。

    對于一個消息隊列只能有一個進程可以注冊到達通知。

    如果 sevp 是 NULL,并且調用進程當前已經在相應的隊列里注冊過通知,則這個注冊被刪除;此后其它進程就可以注冊到這個隊列里以接收通知。

    消息通知只有在一個新消息到達且之前隊列是空的情況下被遞送。如果 mq_notify() 調用時隊列非空,則通知會在隊列變空之后且有新消息到達時遞送。

    如果其它進程或線程正在通過 mq_receive(3) 等待一個空隊列的消息到達,則任何新到達的消息都被忽略:這些消息會傳遞給調用mq_receive(3) 進程或線程,而消息通知注冊仍然有效。

    通知只發生一次:在一個通知遞送之后,這個通知注冊會被刪除,并且其它進程可以注冊一個通知。如果收到消息的進程想接收下一個通知,它可能使用 mq_notify() 請求一個全新通知。這可以在所有未讀消息被收到完之前來執行。(此時把隊列設置非阻塞模式會很有用,在清空隊列消息的時候而不用擔心一旦隊列變空之后被阻塞。)

    返回值成功時,mq_notify() 返回 0;錯誤時,返回 -1,并把 errno 設置為合適的值。 錯誤 EBADF mqdes 指定的描述符無效。 EBUSY 其它進程已經在這個消息隊列里注冊的通知。 EINVAL sevp->sigev_notify 不是一個合法的值;或 sevp->sigev_notify 是SIGEV_SIGNAL 而 sevp->sigev_signo 不是一個信號值。 ENOMEM 內存不足。

    POSIX.1-2008 說當 sevp 是 NULL 時,實現可以產生一個 EINVAL 錯誤,并且調用進程不會被注冊到隊列 mqdes 的通知里。

    mq_send, mq_timedsend - 發送一個消息到消息隊列

    #include <mqueue.h>

    int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); #include <time.h>

     #include <mqueue.h>

     int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout);

    需要 -lrt 來鏈接。

    glibc 需要特性測試宏(參看 feature_test_macros(7)):

    mq_timedsend():

    _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L

    mq_send() 把 msg_ptr 指向的消息加入由 mqdes 引用的消息隊列里。參數 msg_len 指定消息 msg_ptr 的長度:這個長度必須小于或等于隊列 mq_msgsize 屬性的值。零長度的消息是允許。

    msg_prio 是一個用于指定消息優先級的非負整數。消息在隊列里依據優先級排序,相同優先級的消息新消息放于舊消息后面。

    如果消息隊列已經滿了(如當前隊列消息個數等于隊列的 mq_maxmsg 屬性),那么,默認地,mq_send() 會一直阻塞到有足夠的空間來把當前消息入隊,或者在阻塞的時候被一個信號處理器中斷。如果 O_NONBLOCK 標志在消息隊列描述符里有設置,那么調用將直接由 EAGAIN 錯誤返回。

    mq_timedsend() 的行為與 mq_send() 很類似,只是消息隊列滿且 O_NONBLOCK 標志沒有設置時,abs_timeout 指向的結構指定了一個阻塞的軟上限時間。這個上限通過從 Epoch 1970-01-01 00:00:00 +0000 (UTC) 開始的絕對的秒和納秒數指定超時,它的結構定義如下:

    struct timespec { time_t tv_sec; /* 秒 */ long tv_nsec; /* 納秒 */ };

    如果消息隊列滿,并且調用時超時設置已經達到,mq_timedsend() 立刻返回。

    返回值

    成功時,mq_send() 和 mq_timedsend() 返回零;錯誤時,返回 -1,并把 errno 設置為合適的值。

    錯誤 EAGAIN 隊列已滿,并且由 mqdes 消息隊列描述符 O_NONBLOCK 標志設置。 EBADF mqdes 指定的描述符無效。 EINTR 這個調用被信號處理器中斷,參看 signal(7)。 EINVAL 調用需要阻塞,但 abs_timeout 無效,要么因為 tv_sec 小于零,要么因為 tv_nsec小于零或大于 100 百萬。 EMSGSIZE msg_len 大于消息隊列的 mq_msgsize 屬性。 ETIMEDOUT 在消息傳輸完成之前已超時。

     

    mq_receive, mq_timedreceive - 從一個消息隊列里收一條消息 概要 #include <mqueue.h>  ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);  #include <time.h> #include <mqueue.h> ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout);

    需要 -lrt 來鏈接。

    glibc 需要特性測試宏(參看 feature_test_macros(7)):

    mq_timedreceive():

    _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L 描述mq_receive() 從由描述符 mqdes 引用的隊列時刪除優先級最高的最老的消息,并把放置到 msg_ptr 的緩存區內。參數 msg_len 指定緩沖區 msg_ptr 的大小:它必須大于隊列的 mq_msgsize 屬性(參數 mq_getattr(3))。如果 prio 不是 NULL,那么它指向的內存用于返回收到消息相關的優先級。

    如果隊列是空的,默認情況下,mq_receive() 會阻塞到有消息準備好為止,或者被信號處理器中斷為止。如果消息隊列描述符的O_NONBLOCK 標志啟用,則調用會以錯誤 EAGAIN 立即返回。

    mq_timedreceive() 的行為與 mq_receive() 很相似,只不過當隊列是空且 O_NONBLOCK 標志沒有針對相應消息隊列描述符啟用時,調用會阻塞到 abs_timeout 時間點時返回。這個軟上限是一個絕對的時刻值,它計算從 Epoch 1970-01-01 00:00:00 +0000 (UTC) 開始的秒數和納秒數,這個結構的定義如下:

    struct timespec { time_t tv_sec; /* 秒 */ long tv_nsec; /* 納秒 */ }; 如果沒有消息有效,并且超時的時刻已經達到,mq_timedreceive() 立即返回。 返回值成功時,mq_receive() 和 mq_timedreceive() 返回收到的消息字節數;失敗時,-1 被返回,并設置 errno 來指明錯誤。 錯誤 EAGAIN 隊列是空的,并且 O_NONBLOCK 標志在 mqdes 引用的消息隊列描述符上啟用。 EBADF mqdes 指定的描述符無效。 EINTR 這個調用被信號處理器中斷,參看 signal(7)。 EINVAL 調用需要阻塞,但 abs_timeout 無效,要么因為 tv_sec 小于零,要么因為 tv_nsec 小于零或大于 100 百萬。 EMSGSIZE msg_len 小于消息隊列的 mq_msgsize 屬性。 ETIMEDOUT 在消息傳輸完成之前已超時。     mq_unlink - 刪除消息隊列 概要 #include <mqueue.h> int mq_unlink(const char *name);

    需要 -lrt 來鏈接。

    描述mq_unlink() 刪除名為 name 的消息隊列。消息隊列名將被直接刪除。消息隊列本身在所有引用這個隊列的描述符被關閉時銷毀。 返回值成功時 mq_unlink() 返回0;錯誤時,返回 -1,并把 errno 設置為合適的值。 錯誤 EACCES 調用者沒有權限刪除這個消息隊列。 ENAMETOOLONG name 太長了。 ENOENT 沒有名為 name 的消息隊列。mq_overview - POSIX 消息隊列概述 描述POSIX 消息隊列允許進程以消息的形式交換數據。這組 API 與 System V 的消息隊列(msgget(2)、msgsnd(2)、msgrcv(2) 等等)有所不同,但是提供了相似的功能。

    消息隊列通過 mq_open(3) 創建和打開,這個函數返回一個 消息隊列描述符 (mqd_t),它將在之后調用中被用于引用那個打開的消息隊列。每個消息隊列都通過形如 /somename 的名字來區分,這是一個包含起始斜杠在內的最大長度不超過 NAME_MAX(如 225)的以空字符結尾的字符串,在起始斜杠之后不允許再有斜杠。兩個進程可能通過在使用 mq_open(3) 時傳遞相同的名字來打開相同的消息隊列。

    消息可以使用 mq_send(3) 和 mq_receive(3) 在一個隊列里傳入和傳出。當一個進程不再使用隊列時,可以通過 mq_close(3) 來關閉它,并且要是這個隊列在將來也不會使用時,可以通過 mq_unlink(3) 來刪除它。隊列屬性可以通過 mq_getattr(3) 和 mq_setattr(3) 來取得和更改(在一些情況下)。一個進程可以使用 mq_notify(3) 在一個空的隊列時請求異步的卡片消息到達通知。

    一個消息隊列描述符引用一個 消息隊列打開描述符 (參考 open(2))。在調用 fork(2) 之后,子進程繼承了父親消息隊列描述符的復本,并且這些描述符引用與父親中相應描述符相同消息隊列打開描述符。在兩個進程里相關描述符共享消息隊列打開描述符相關的標志位(mq_flags)。

    每個消息都有一個相關的 優先級,并且高優先級的消息總是首先傳遞給接收進程。消息優先級范圍在 0(低優先級) 到sysconf(_SC_MQ_PRIO_MAX) - 1 (高優先級)。在 Linux 系統里,sysconf(_SC_MQ_PRIO_MAX) 返回 32768,但是 POSIX.1-2001 只要求實現提供優先級范圍 0 到 31;一些實現只提供了這個范圍。

      版本POSIX 消息隊列 Linux 內核從 2.6.6 開始支持。Glibc 從版本 2.3.4 開始支持。 內核選項對 POSIX 消息隊列的支持可以內核配制選項 CONFIG_POSIX_MQUEUE 來控制。這個選項在默認是打開的。 生命期(持續性)POSIX 消息隊列是內核生命期的;如果沒有使用mq_unlink(3) 刪除的話,一個消息隊列會一直存在,直到系統關閉。 鏈接使用 POSIX 消息隊列 API 的程序必須在鏈接的時候加入選項cc -lrt 來鏈接實時庫,librt。 /proc 接口下列接口可以用于限制 POSIX 消息隊列消耗的內存數目: /proc/sys/fs/mqueue/msg_max 這個文件可以用于查看和更改隊列里緩存的軟最大消息數目。這個值是 mq_open(3) 中參數 attr->mq_maxmsg 的軟上限。msg_max 的默認值是 10。最小允許的值是 1(在內核 2.6.28 前是 10)。物理上限是 HARD_MAX(131072 / sizeof(void *)) (在 Linux/86 上是 32678)。這個軟限制可以被特權(CAP_SYS_RESOURCE)進程忽略,但是 HARD_MAX 不能被突破。 /proc/sys/fs/mqueue/msgsize_max 這個文件可以用于查看和更改最大消息長度的軟上限。這個值作用于 mq_open(3) 的參數 attr->mq_msgsizemsgsize_max 的默認值是 8192 個字節。允許的最小值是 128(在 2.6.28 內核之前是 8192)。msgsize_max 的上限是 1,048,576(內核 2.6.28 之前上限是 INT_MAX:對于 Linux/86 而言是 2,147,483,647 )。這個限制可以被特權(CAP_SYS_RESOURCE)進程忽略。 /proc/sys/fs/mqueue/queues_max 這個文件可以用于查看和更改系統范圍內的消息隊列個數的限制。一旦這個限制達到了,只有特權進程(CAP_SYS_RESOURCE)可以創建新的隊列。queues_max 的默認值是 256,它可以被更改為 0 到 INT_MAX 的任何值。資源限制RLIMIT_MSGQUEUE 是一個資源限制值,它限制進程真實 UID 可以用于消息的最大內存數目。在 getrlimit(2) 中有詳細說明。 掛載消息隊列文件系統在 Linux 系統里,已創建的消息隊列在一個虛擬的文件系統里。(其它實現可能也提供類似的特性,但具體細節可能不同。)這個文件系統可以(被超級用戶)使用下面命令掛載: # mkdir /dev/mqueue # mount -t mqueue none /dev/mqueue 粘滯位會自動在掛載的目錄打開。

    一旦這個文件系統被掛載,系統里的消息隊列就可以使用大家熟悉的命令(如 ls(1) 和 rm(1))來查看和維護了。

    目錄里的每一個文件都只包含相應隊列信息一行內容:

    $ cat /dev/mqueue/mymq QSIZE:129 NOTIFY:2 SIGNO:0 NOTIFY_PID:8260 這些域的含意如下: QSIZE 隊列里所有消息的總字節數 NOTIFY_PID 如果這不是零,那么 進程號為 PID 進程已經使用 mq_notify(3) 來注冊異步消息通知,并且剩余的域用來描述通知如何發出。 NOTIFY 通知方式:0 是 SIGEV_SIGNAL;1 是 SIGEV_NONE;以及 2 是 SIGEV_THREAD。 SIGNO 對于 SIGEV_SIGNAL 方式所使用信號數字。輪詢消息隊列描述符在 Linux 里,一個消息隊列描述符是一個真實的文件描述符,凍僵可以使用 select(2)、poll(2) 或 epoll(7) 來監視。這不具移植性。     mq_overview - POSIX 消息隊列概述 描述POSIX 消息隊列允許進程以消息的形式交換數據。這組 API 與 System V 的消息隊列(msgget(2)、msgsnd(2)、msgrcv(2) 等等)有所不同,但是提供了相似的功能。

    消息隊列通過 mq_open(3) 創建和打開,這個函數返回一個 消息隊列描述符 (mqd_t),它將在之后調用中被用于引用那個打開的消息隊列。每個消息隊列都通過形如 /somename 的名字來區分,這是一個包含起始斜杠在內的最大長度不超過 NAME_MAX(如 225)的以空字符結尾的字符串,在起始斜杠之后不允許再有斜杠。兩個進程可能通過在使用 mq_open(3) 時傳遞相同的名字來打開相同的消息隊列。

    消息可以使用 mq_send(3) 和 mq_receive(3) 在一個隊列里傳入和傳出。當一個進程不再使用隊列時,可以通過 mq_close(3) 來關閉它,并且要是這個隊列在將來也不會使用時,可以通過 mq_unlink(3) 來刪除它。隊列屬性可以通過 mq_getattr(3) 和 mq_setattr(3) 來取得和更改(在一些情況下)。一個進程可以使用 mq_notify(3) 在一個空的隊列時請求異步的卡片消息到達通知。

    一個消息隊列描述符引用一個 消息隊列打開描述符 (參考 open(2))。在調用 fork(2) 之后,子進程繼承了父親消息隊列描述符的復本,并且這些描述符引用與父親中相應描述符相同消息隊列打開描述符。在兩個進程里相關描述符共享消息隊列打開描述符相關的標志位(mq_flags)。

    每個消息都有一個相關的 優先級,并且高優先級的消息總是首先傳遞給接收進程。消息優先級范圍在 0(低優先級) 到sysconf(_SC_MQ_PRIO_MAX) - 1 (高優先級)。在 Linux 系統里,sysconf(_SC_MQ_PRIO_MAX) 返回 32768,但是 POSIX.1-2001 只要求實現提供優先級范圍 0 到 31;一些實現只提供了這個范圍。

    POSIX 消息隊列 Linux 內核從 2.6.6 開始支持。Glibc 從版本 2.3.4 開始支持。 內核選項對 POSIX 消息隊列的支持可以內核配制選項CONFIG_POSIX_MQUEUE 來控制。這個選項在默認是打開的。 生命期(持續性)POSIX 消息隊列是內核生命期的;如果沒有使用mq_unlink(3) 刪除的話,一個消息隊列會一直存在,直到系統關閉。 鏈接使用 POSIX 消息隊列 API 的程序必須在鏈接的時候加入選項cc -lrt 來鏈接實時庫,librt。 /proc 接口下列接口可以用于限制 POSIX 消息隊列消耗的內存數目: /proc/sys/fs/mqueue/msg_max 這個文件可以用于查看和更改隊列里緩存的軟最大消息數目。這個值是 mq_open(3) 中參數 attr->mq_maxmsg 的軟上限。msg_max 的默認值是 10。最小允許的值是 1(在內核 2.6.28 前是 10)。物理上限是 HARD_MAX(131072 / sizeof(void *)) (在 Linux/86 上是 32678)。這個軟限制可以被特權(CAP_SYS_RESOURCE)進程忽略,但是 HARD_MAX 不能被突破。 /proc/sys/fs/mqueue/msgsize_max 這個文件可以用于查看和更改最大消息長度的軟上限。這個值作用于 mq_open(3) 的參數 attr->mq_msgsizemsgsize_max 的默認值是 8192 個字節。允許的最小值是 128(在 2.6.28 內核之前是 8192)。msgsize_max 的上限是 1,048,576(內核 2.6.28 之前上限是 INT_MAX:對于 Linux/86 而言是 2,147,483,647 )。這個限制可以被特權(CAP_SYS_RESOURCE)進程忽略。 /proc/sys/fs/mqueue/queues_max 這個文件可以用于查看和更改系統范圍內的消息隊列個數的限制。一旦這個限制達到了,只有特權進程(CAP_SYS_RESOURCE)可以創建新的隊列。queues_max 的默認值是 256,它可以被更改為 0 到 INT_MAX 的任何值。資源限制RLIMIT_MSGQUEUE 是一個資源限制值,它限制進程真實 UID 可以用于消息的最大內存數目。在 getrlimit(2) 中有詳細說明。 掛載消息隊列文件系統在 Linux 系統里,已創建的消息隊列在一個虛擬的文件系統里。(其它實現可能也提供類似的特性,但具體細節可能不同。)這個文件系統可以(被超級用戶)使用下面命令掛載: # mkdir /dev/mqueue # mount -t mqueue none /dev/mqueue 粘滯位會自動在掛載的目錄打開。

    一旦這個文件系統被掛載,系統里的消息隊列就可以使用大家熟悉的命令(如 ls(1) 和 rm(1))來查看和維護了。

    目錄里的每一個文件都只包含相應隊列信息一行內容:

    $ cat /dev/mqueue/mymq QSIZE:129 NOTIFY:2 SIGNO:0 NOTIFY_PID:8260 這些域的含意如下: QSIZE 隊列里所有消息的總字節數 NOTIFY_PID 如果這不是零,那么 進程號為 PID 進程已經使用 mq_notify(3) 來注冊異步消息通知,并且剩余的域用來描述通知如何發出。 NOTIFY 通知方式:0 是 SIGEV_SIGNAL;1 是 SIGEV_NONE;以及 2 是 SIGEV_THREAD。 SIGNO 對于 SIGEV_SIGNAL 方式所使用信號數字。輪詢消息隊列描述符在 Linux 里,一個消息隊列描述符是一個真實的文件描述符,凍僵可以使用 select(2)、poll(2) 或epoll(7) 來監視。這不具移植性。 遵循于POSIX.1-2001. 注意System V 消息隊列(msgget(2)、msgsnd(2)、msgrcv(2) 等等)是一組老的用于進程交互消息的 API 。POSIX 消息隊列提供了一組優于 System V 消息隊列的接口設計;另一方面 POSIX 消息隊列又不如 System V 消息隊列受到的支持程度好(尤其是老的系統里)。

    目前(2.6.26) Linux 不支持在 POSIX 消息隊列里應用訪問控制列表(ACLs)。

    ====================================================

    消息隊列system v接口API

    int msgget(key_t key, int msgflg);

    描述

    msgget() 系統調用返回一個與參數 key 相關聯的消息隊列標識符。如果這個 key是值 IPC_PRIVATE 或 key 不是 IPC_PRIVATE 而又不存在關聯于給定key 的消息隊列并且 IPC_CREAT 在 msgflg中指定,那么一個新的消息隊列被創建。

    如果 msgflg 同時指定了 IPC_CREAT 和 IPC_EXCL 并且一個關聯key 的消息隊列存在,則 msgget() 將失敗并且設置 errnoEEXIST。(這與 open(2) 組合O_CREAT | O_EXCL 有相同效果。)

    如果創建了消息,則參數 msgflg 有意義的最后幾個位定義了消息隊列的權限。這些權限位的格式與語義同open(2) 中的 mode參數相同。(執行權限沒有使用。)

    如果新消息隊列被創建了,那么它關聯的 msqid_ds 結構(參考 msgctl(2))按如下方式初始化:

    msg_perm.cuid 和 msg_perm.uid 被設置用調用進程的有效用戶ID。

    msg_perm.cgid 和 msg_perm.gid 設置為調用進程的有效組 ID。

    msg_perm.mode 最后有效的 9 個位使用 msgflg 最后有效的 9個位來設置。

    msg_qnummsg_lspidmsg_lrpidmsg_stime和 msg_rtime 都設置為 0。

    msg_ctime 設置為當前時間。

    msg_qbytes 設置為系統限制 MSGMNB

     

    如果一個消息隊列已經存在并且權限認證通過,則會額外查看一下隊列是不是被標志為釋放。

    返回值如果成功,返回值將是消息隊列標識符(一個非負整數),否則的話 -1 被返回并設置 errno 來指明錯誤。錯誤如果失敗,errno 可能被設置為如下值:EACCES已經有一個關聯于 key 的消息隊列,但是調用進程沒有對這個隊列的訪問權限,同時這個進程沒有CAP_IPC_OWNER 特權。

    EEXIST關聯 key 的消息隊列已經存在而 msgflg 卻同時設置了 IPC_CREAT和 IPC_EXCL

    ENOENT不存在關聯于 key 的消息隊列可 msgflg 沒有指定IPC_CREAT

    ENOMEM必需創建一個消息隊列但系統沒有足夠的內存來建立相應的數據結構。

    ENOSPC必需創建一個消息隊列但是系統允許的最大消息隊列個數(MSGMNI) 已經達到。遵循于SVr4, POSIX.1-2001。注意IPC_PRIVATE 不是一個標志域而一個 key_t 類型的值。如果使用這一個特殊值作為keymsgflg 除了最后 9 位以外的其它內容都會被系統調用忽略,并且新建一個(成功)消息。

    下面是一些對 msgget() 有效果的系統限制:

    MSGMNI系統范圍內的消息隊列最大數目:策略相關的(在 Linux 系統里,這個限制可能通過/proc/sys/kernel/msgmni 讀取和悠。

     

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

    參數: 
    msqid:消息隊列的識別碼。
    msgp:指向消息緩沖區的指針,此位置用來暫時存儲發送和接收的消息,是一個用戶可定義的通用結構,形態如下

    struct msgbuf {
    long mtype; 
    char mtext[1]; 
    };

    msgsz:消息的大小。
    msgtyp:從消息隊列內讀取的消息形態。如果值為零,則表示消息隊列中的所有消息都會被讀取。
    msgflg:用來指明核心程序在隊列沒有數據的情況下所應采取的行動。如果msgflg和常數IPC_NOWAIT合用,則在msgsnd()執行時若是消息隊列已滿,則msgsnd()將不會阻塞,而會立即返回-1,如果執行的是msgrcv(),則在消息隊列呈空時,不做等待馬上返回-1,并設定錯誤碼為ENOMSG。當msgflg為0時,msgsnd()及msgrcv()在隊列呈滿或呈空的情形時,采取阻塞等待的處理模式。



    返回說明: 
    成功執行時,msgsnd()返回0,msgrcv()返回拷貝到mtext數組的實際字節數。失敗兩者都返回-1,errno被設為以下的某個值
    [對于msgsnd] 
    EACCES:調用進程在消息隊列上沒有寫權能,同時沒有CAP_IPC_OWNER權能
    EAGAIN:由于消息隊列的msg_qbytes的限制和msgflg中指定IPC_NOWAIT標志,消息不能被發送
    EFAULT:msgp指針指向的內存空間不可訪問
    EIDRM:消息隊列已被刪除
    EINTR:等待消息隊列空間可用時被信號中斷
    EINVAL:參數無效
    ENOMEM:系統內存不足,無法將msgp指向的消息拷貝進來
    [對于msgrcv]
    E2BIG:消息文本長度大于msgsz,并且msgflg中沒有指定MSG_NOERROR
    EACCES:調用進程沒有讀權能,同時沒具有CAP_IPC_OWNER權能
    EAGAIN:消息隊列為空,并且msgflg中沒有指定IPC_NOWAIT
    EFAULT:msgp指向的空間不可訪問
    EIDRM:當進程睡眠等待接收消息時,消息已被刪除
    EINTR:當進程睡眠等待接收消息時,被信號中斷
    EINVAL:參數無效
    ENOMSG:msgflg中指定了IPC_NOWAIT,同時所請求類型的消息不存在

    int msgctl(int msqid, int cmd, struct msqid_ds *buf)


    msgctl 系統調用對 msgqid 標識的消息隊列執行 cmd 操作,系統定義了 3 種 cmd 操作: IPC_STAT ,  IPC_SET , IPC_RMID ,意義分別如下:

    • IPC_STAT :  該命令用來獲取消息隊列對應的 msqid_ds 數據結構,并將其保存到 buf  指定的地址空間。
    • IPC_SET :    該命令用來設置消息隊列的屬性,要設置的屬性存儲在 buf 中,可設置的屬性包括: msg_perm.uid , msg_perm.gid , msg_perm.mode 以及 msg_qbytes .
    • IPC_RMID :  從內核中刪除 msqid 標識的消息隊列。
    當cmd是IPC_RMID時,buf指定為NULL,對msqid對應的消息隊列進行刪除 當cmd是IPC_SET 時,將buf  set為  msqid對應的消息隊列 當cmd是IPC_STAT ,將msqid對應的消息隊列 get到buf RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全