1. 程式人生 > >消息隊列函數(msgget、msgctl、msgsnd、msgrcv)小記學習

消息隊列函數(msgget、msgctl、msgsnd、msgrcv)小記學習

nowait aci 使用 信號中斷 row 返回 cti 標識符 fault

一、什麽是消息隊列
消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。 每個數據塊都被認為含有一個類型,接收進程可以獨立地接收含有不同類型的數據結構。我們可以通過發送消息來避免命名管道的同步和阻塞問題。但是消息隊列與命名管道一樣,每個數據塊都有一個最大長度的限制。

Linux用宏MSGMAX和MSGMNB來限制一條消息的最大長度和一個隊列的最大長度。

二、在Linux中使用消息隊列
Linux提供了一系列消息隊列的函數接口來讓我們方便地使用它來實現進程間的通信。消息隊列函數由msgget、msgctl、msgsnd、msgrcv四個函數組成。下面的表格列出了這四個函數的函數原型及其具體說明。

1. msgget函數原型

msgget(得到消息隊列標識符或創建一個消息隊列對象)

所需頭文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數說明

得到消息隊列標識符或創建一個消息隊列對象並返回消息隊列標識符

函數原型

int msgget(key_t key, int msgflg)

函數傳入值

key

0(IPC_PRIVATE):會建立新的消息隊列

大於0的32位整數:視參數msgflg來確定操作。通常要求此值來源於ftok返回的IPC鍵值

msgflg

0:取消息隊列標識符,若不存在則函數會報錯

IPC_CREAT:當msgflg&IPC_CREAT為真時,如果內核中不存在鍵值與key相等的消息隊列,則新建一個消息隊列;如果存在這樣的消息隊列,返回此消息隊列的標識符

IPC_CREAT|IPC_EXCL:如果內核中不存在鍵值與key相等的消息隊列,則新建一個消息隊列;如果存在這樣的消息隊列則報錯

函數返回值

成功:返回消息隊列的標識符

出錯:-1,錯誤原因存於error中

附加說明

上述msgflg參數為模式標誌參數,使用時需要與IPC對象存取權限(如0600)進行|運算來確定消息隊列的存取權限

錯誤代碼

EACCES:指定的消息隊列已存在,但調用進程沒有權限訪問它

EEXIST:key指定的消息隊列已存在,而msgflg中同時指定IPC_CREAT和IPC_EXCL標誌

ENOENT:key指定的消息隊列不存在同時msgflg中沒有指定IPC_CREAT標誌

ENOMEM:需要建立消息隊列,但內存不足

ENOSPC:需要建立消息隊列,但已達到系統的限制

如果用msgget創建了一個新的消息隊列對象時,則msqid_ds結構成員變量的值設置如下:

msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime設置為0。

msg_ctime設置為當前時間。

msg_qbytes設成系統的限制值。

msgflg的讀寫權限寫入msg_perm.mode中。

msg_perm結構的uid和cuid成員被設置成當前進程的有效用戶ID,gid和cuid成員被設置成當前進程的有效組ID。

2. msgctl函數原型

msgctl (獲取和設置消息隊列的屬性)

所需頭文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數說明

獲取和設置消息隊列的屬性

函數原型

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

函數傳入值

msqid

消息隊列標識符

cmd

IPC_STAT:獲得msgid的消息隊列頭數據到buf中

IPC_SET:設置消息隊列的屬性,要設置的屬性需先存儲在buf中,可設置的屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes

buf

消息隊列管理結構體,請參見消息隊列內核結構說明部分

函數返回值

成功:0

出錯:-1,錯誤原因存於error中

錯誤代碼

EACCESS:參數cmd為IPC_STAT,確無權限讀取該消息隊列

EFAULT:參數buf指向無效的內存地址

EIDRM:標識符為msqid的消息隊列已被刪除

EINVAL:無效的參數cmd或msqid

EPERM:參數cmd為IPC_SET或IPC_RMID,卻無足夠的權限執行

3. msgsnd函數原型

msgsnd (將消息寫入到消息隊列)

所需頭文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數說明

將msgp消息寫入到標識符為msqid的消息隊列

函數原型

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

函數傳入值

msqid

消息隊列標識符

msgp

發送給隊列的消息。msgp可以是任何類型的結構體,但第一個字段必須為long類型,即表明此發送消息的類型,msgrcv根據此接收消息。msgp定義的參照格式如下:

struct s_msg{ /*msgp定義的參照格式*/
long type; /* 必須大於0,消息類型 */
char mtext[256]; /*消息正文,可以是其他任何類型*/
} msgp;

msgsz

要發送消息的大小,不含消息類型占用的4個字節,即mtext的長度

msgflg

0:當消息隊列滿時,msgsnd將會阻塞,直到消息能寫進消息隊列

IPC_NOWAIT:當消息隊列已滿的時候,msgsnd函數不等待立即返回

IPC_NOERROR:若發送的消息大於size字節,則把該消息截斷,截斷部分將被丟棄,且不通知發送進程。

函數返回值

成功:0

出錯:-1,錯誤原因存於error中

錯誤代碼

EAGAIN:參數msgflg設為IPC_NOWAIT,而消息隊列已滿

EIDRM:標識符為msqid的消息隊列已被刪除

EACCESS:無權限寫入消息隊列

EFAULT:參數msgp指向無效的內存地址

EINTR:隊列已滿而處於等待情況下被信號中斷

EINVAL:無效的參數msqid、msgsz或參數消息類型type小於0

msgsnd()為阻塞函數,當消息隊列容量滿或消息個數滿會阻塞。消息隊列已被刪除,則返回EIDRM錯誤;被信號中斷返回E_INTR錯誤。

如果設置IPC_NOWAIT消息隊列滿或個數滿時會返回-1,並且置EAGAIN錯誤。

msgsnd()解除阻塞的條件有以下三個條件:

① 不滿足消息隊列滿或個數滿兩個條件,即消息隊列中有容納該消息的空間。

② msqid代表的消息隊列被刪除。

③ 調用msgsnd函數的進程被信號中斷。

4. msgrcv函數原型

msgrcv (從消息隊列讀取消息)

所需頭文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函數說明

從標識符為msqid的消息隊列讀取消息並存於msgp中,讀取後把此消息從消息隊列中刪除

函數原型

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

函數傳入值

msqid

消息隊列標識符

msgp

存放消息的結構體,結構體類型要與msgsnd函數發送的類型相同

msgsz

要接收消息的大小,不含消息類型占用的4個字節

msgtyp

0:接收第一個消息

>0:接收類型等於msgtyp的第一個消息

<0:接收類型等於或者小於msgtyp絕對值的第一個消息

msgflg

0: 阻塞式接收消息,沒有該類型的消息msgrcv函數一直阻塞等待

IPC_NOWAIT:如果沒有返回條件的消息調用立即返回,此時錯誤碼為ENOMSG

IPC_EXCEPT:與msgtype配合使用返回隊列中第一個類型不為msgtype的消息

IPC_NOERROR:如果隊列中滿足條件的消息內容大於所請求的size字節,則把該消息截斷,截斷部分將被丟棄

函數返回值

成功:實際讀取到的消息數據長度

出錯:-1,錯誤原因存於error中

錯誤代碼

E2BIG:消息數據長度大於msgsz而msgflag沒有設置IPC_NOERROR

EIDRM:標識符為msqid的消息隊列已被刪除

EACCESS:無權限讀取該消息隊列

EFAULT:參數msgp指向無效的內存地址

ENOMSG:參數msgflg設為IPC_NOWAIT,而消息隊列中無消息可讀

EINTR:等待讀取隊列內的消息情況下被信號中斷

msgrcv()解除阻塞的條件有以下三個:

① 消息隊列中有了滿足條件的消息。

② msqid代表的消息隊列被刪除。

③ 調用msgrcv()的進程被信號中斷。

消息隊列函數(msgget、msgctl、msgsnd、msgrcv)小記學習