Linux訊息佇列詳解
阿新 • • 發佈:2019-02-11
Linux的訊息佇列(queue)實質上是一個連結串列, 它有訊息佇列識別符號(queue ID). msgget建立一個新佇列或開啟一個存在的佇列; msgsnd向佇列末端新增一條新訊息; msgrcv從佇列中取訊息, 取訊息是不一定遵循先進先出的, 也可以按訊息的型別欄位取訊息.
1. 識別符號(des)和鍵(key):
訊息佇列, 訊號量和共享儲存段, 都屬於核心中的IPC結構, 它們都用識別符號來描述. 這個識別符號是一個非負整數, 與檔案描述符不同的是, 建立時並不會重複利用通過刪除回收的整數, 而是每次+1, 直到整數最大值迴轉到0.
識別符號是IPC物件的內部名, 而它的外部名則是key(鍵), 它的基本型別是key_t, 在標頭檔案<sys/types.h>中定義為長整型. 鍵由核心變換成識別符號.
2. 訊息佇列狀態msqid_ds:
每個訊息佇列都有一個msqid_ds結構與其關聯:
struct msqid_ds
{
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
結構體ipc_perm: http://blog.csdn.net/yuzhoudiwang/article/details/4377064
3. 由路徑名和專案ID產生一個key:
如果客戶程序和伺服器程序認同一個路徑名和專案ID(0~255間的字元值), 接著呼叫ftok將這兩個值變換為一個key.
原型: key_t ftok(const char *path, int id);
標頭檔案: <sys/ipc.h>
返回值: 成功則返回key, 出錯則返回(key_t)-1.
引數: path引數必須引用一個現存檔案. 當產生key時 只使用id引數的低8位.
說 明: 如果兩個路徑名引用兩個不同的檔案, 對這兩個路徑名呼叫ftok通常返回不同的key. 但是, 因為i節點號和key通常存放在長整型中, 於是建立key時可能會丟失資訊. 這意味著, 如果使用同一專案ID, 那麼對於不同檔案的兩個路徑名可能產生相同的key. 該函式的工作方式為:
按給定的路徑名取得其stat結構.
從該結構中取出部分st_dev和st_ino欄位, 與專案ID組合起來.
4. 建立/開啟訊息佇列:
msgget可以建立一個新佇列或開啟一個存在的佇列.
原型: int msgget(key_t key, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回訊息佇列ID, 出錯則返回-1.
引數:
key: 訊息佇列的key值.
flag: 標誌位.
說明:
建立佇列有兩種方法:
key是IPC_PRIVATE.
key當前未與特定型別的IPC結構相結合, 並且flag中指定了IPC_CREAT位.
初始化msqid_ds成員:
ipc_perm中的mode成員按flag進行設定.
msg_qnum, msg_lspid, msg_lrpid, msg_stime和msg_rtime都設定為0.
msg_ctime設定為當前時間.
msg_qbytes設定為系統限制值.
5. 訊息佇列的垃圾桶函式:
msgctl類似於驅動程式中的ioctl函式, 可對訊息佇列執行多種操作.
原型: int msgctl(int msqid, int cmd, struct msgqid_ds *buf);
標頭檔案: <sys/msg.h>
返回值: 成功則返回0, 出錯則返回-1.
引數: cmd引數說明對msqid指定的佇列要執行的命令:
IPC_STAT: 取此佇列的msqid_ds結構, 並將它存放在buf指向的結構中.
IPC_SET: 按由buf指向結構中的值, 設定與此佇列相關結構中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. 該命令只有下列兩種程序可以執行:
有效使用者ID等於msg_perm.cuid或msg_per.uid.
具有超級使用者特權的程序.
IPC_RMID: 從系統中刪除該訊息佇列以及仍在該佇列中的所有資料. 執行許可權同上.
6. 將資料放到訊息佇列:
呼叫msgsnd將資料放到訊息佇列中.
原型: int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回0, 出錯則返回-1.
說 明: 可以定義一個訊息結構, 結構中帶型別, 這樣就可用非先進先出順序取訊息了. 當msgsnd成功返回, 與訊息佇列相關的msqid_ds結構得到更新, 以標明發出該呼叫的程序ID(msg_lsqid), 進行該呼叫的時間(msg_stime), 並指示佇列中增加了一條訊息(msg_qnum).
7. 從訊息佇列中取訊息:
呼叫msgrcv將從訊息佇列中取訊息.
原型: ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回訊息的資料部分的長度, 出錯則返回-1.
引數:
ptr: 指向一個長整型數(返回的訊息型別存放在其中), 跟隨其後的是存放實際訊息資料的緩衝區.
nbytes: 資料緩衝區的長度. 若返回的訊息大於nbytes, 且在flag中設定了MSG_NOERROR, 則該訊息被截短.
type:
type == 0: 返回佇列中的第一個訊息.
type > 0: 返回佇列中訊息型別為type的第一個訊息.
type < 0: 返回佇列中訊息型別值小於或等於type絕對值的訊息, 如果這種訊息有若干個, 則取型別值最小的訊息.
1. 識別符號(des)和鍵(key):
訊息佇列, 訊號量和共享儲存段, 都屬於核心中的IPC結構, 它們都用識別符號來描述. 這個識別符號是一個非負整數, 與檔案描述符不同的是, 建立時並不會重複利用通過刪除回收的整數, 而是每次+1, 直到整數最大值迴轉到0.
識別符號是IPC物件的內部名, 而它的外部名則是key(鍵), 它的基本型別是key_t, 在標頭檔案<sys/types.h>中定義為長整型. 鍵由核心變換成識別符號.
2. 訊息佇列狀態msqid_ds:
每個訊息佇列都有一個msqid_ds結構與其關聯:
struct msqid_ds
{
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
結構體ipc_perm:
3. 由路徑名和專案ID產生一個key:
如果客戶程序和伺服器程序認同一個路徑名和專案ID(0~255間的字元值), 接著呼叫ftok將這兩個值變換為一個key.
原型: key_t ftok(const char *path, int id);
標頭檔案: <sys/ipc.h>
返回值: 成功則返回key, 出錯則返回(key_t)-1.
引數: path引數必須引用一個現存檔案. 當產生key時 只使用id引數的低8位.
說 明: 如果兩個路徑名引用兩個不同的檔案, 對這兩個路徑名呼叫ftok通常返回不同的key. 但是, 因為i節點號和key通常存放在長整型中, 於是建立key時可能會丟失資訊. 這意味著, 如果使用同一專案ID, 那麼對於不同檔案的兩個路徑名可能產生相同的key. 該函式的工作方式為:
按給定的路徑名取得其stat結構.
從該結構中取出部分st_dev和st_ino欄位, 與專案ID組合起來.
4. 建立/開啟訊息佇列:
msgget可以建立一個新佇列或開啟一個存在的佇列.
原型: int msgget(key_t key, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回訊息佇列ID, 出錯則返回-1.
引數:
key: 訊息佇列的key值.
flag: 標誌位.
說明:
建立佇列有兩種方法:
key是IPC_PRIVATE.
key當前未與特定型別的IPC結構相結合, 並且flag中指定了IPC_CREAT位.
初始化msqid_ds成員:
ipc_perm中的mode成員按flag進行設定.
msg_qnum, msg_lspid, msg_lrpid, msg_stime和msg_rtime都設定為0.
msg_ctime設定為當前時間.
msg_qbytes設定為系統限制值.
5. 訊息佇列的垃圾桶函式:
msgctl類似於驅動程式中的ioctl函式, 可對訊息佇列執行多種操作.
原型: int msgctl(int msqid, int cmd, struct msgqid_ds *buf);
標頭檔案: <sys/msg.h>
返回值: 成功則返回0, 出錯則返回-1.
引數: cmd引數說明對msqid指定的佇列要執行的命令:
IPC_STAT: 取此佇列的msqid_ds結構, 並將它存放在buf指向的結構中.
IPC_SET: 按由buf指向結構中的值, 設定與此佇列相關結構中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. 該命令只有下列兩種程序可以執行:
有效使用者ID等於msg_perm.cuid或msg_per.uid.
具有超級使用者特權的程序.
IPC_RMID: 從系統中刪除該訊息佇列以及仍在該佇列中的所有資料. 執行許可權同上.
6. 將資料放到訊息佇列:
呼叫msgsnd將資料放到訊息佇列中.
原型: int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回0, 出錯則返回-1.
說 明: 可以定義一個訊息結構, 結構中帶型別, 這樣就可用非先進先出順序取訊息了. 當msgsnd成功返回, 與訊息佇列相關的msqid_ds結構得到更新, 以標明發出該呼叫的程序ID(msg_lsqid), 進行該呼叫的時間(msg_stime), 並指示佇列中增加了一條訊息(msg_qnum).
7. 從訊息佇列中取訊息:
呼叫msgrcv將從訊息佇列中取訊息.
原型: ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
標頭檔案: <sys/msg.h>
返回值: 成功則返回訊息的資料部分的長度, 出錯則返回-1.
引數:
ptr: 指向一個長整型數(返回的訊息型別存放在其中), 跟隨其後的是存放實際訊息資料的緩衝區.
nbytes: 資料緩衝區的長度. 若返回的訊息大於nbytes, 且在flag中設定了MSG_NOERROR, 則該訊息被截短.
type:
type == 0: 返回佇列中的第一個訊息.
type > 0: 返回佇列中訊息型別為type的第一個訊息.
type < 0: 返回佇列中訊息型別值小於或等於type絕對值的訊息, 如果這種訊息有若干個, 則取型別值最小的訊息.