linux c程式設計:System V訊息佇列一
訊息佇列可以認為是一個訊息連結串列,System V 訊息佇列使用訊息佇列識別符號標識。具有足
夠特權的任何程序都可以往一個佇列放置一個訊息,具有足夠特權的任何程序都可以從一個給定佇列讀出一個訊息。在某個程序往一個佇列寫入訊息之前,並不需要另外某個程序在該佇列上等待訊息的到達。System V 訊息佇列是隨核心持續的,只有在核心重起或者顯示刪除一個訊息佇列時,該訊息佇列才會真正被刪除。可以將核心中的某個特定的訊息佇列畫為一個訊息連結串列,如下圖所示:
對於系統中每個訊息佇列,核心維護一個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 */
};
System V 訊息佇列操作函式
系統V訊息佇列API共有四個,使用時需要包括幾個標頭檔案:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
1)int msgget(key_t key, int msgflg)
引數key是一個鍵值,由ftok獲得;msgflg引數是一些標誌位。該呼叫返回與健值key相對應的訊息佇列描述字。
在以下兩種情況下,該呼叫將建立一個新的訊息佇列:
-
如果沒有訊息佇列與健值key相對應,並且msgflg中包含了IPC_CREAT標誌位;
-
key引數為IPC_PRIVATE;
引數msgflg可以為以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或結果。
呼叫返回:成功返回訊息佇列描述字,否則返回-1。
注:引數key設定成常數IPC_PRIVATE並不意味著其他程序不能訪問該訊息佇列,只意味著即將建立新的訊息佇列。
2)int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
該系統呼叫從msgid代表的訊息佇列中讀取一個訊息,並把訊息儲存在msgp指向的msgbuf結構中。
msqid為訊息佇列描述字;訊息返回後儲存在msgp指向的地址,msgsz指定msgbuf的mtext成員的長度(即訊息內容的長度),msgtyp為請求讀取的訊息型別;讀訊息標誌msgflg可以為以下幾個常值的或:
-
IPC_NOWAIT 如果沒有滿足條件的訊息,呼叫立即返回,此時,errno=ENOMSG
-
IPC_EXCEPT 與msgtyp>0配合使用,返回佇列中第一個型別不為msgtyp的訊息
-
IPC_NOERROR 如果佇列中滿足條件的訊息內容大於所請求的msgsz位元組,則把該訊息截斷,截斷部分將丟失。
msgrcv手冊中詳細給出了訊息型別取不同值時(>0; <0; =0),呼叫將返回訊息佇列中的哪個訊息。
msgrcv()解除阻塞的條件有三個:
-
訊息佇列中有了滿足條件的訊息;
-
msqid代表的訊息佇列被刪除;
-
呼叫msgrcv()的程序被訊號中斷;
呼叫返回:成功返回讀出訊息的實際位元組數,否則返回-1。
3)int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
向msgid代表的訊息佇列傳送一個訊息,即將傳送的訊息儲存在msgp指向的msgbuf結構中,訊息的大小由msgze指定。
對傳送訊息來說,有意義的msgflg標誌為IPC_NOWAIT,指明在訊息佇列沒有足夠空間容納要傳送的訊息時,msgsnd是否等待。造成msgsnd()等待的條件有兩種:
-
當前訊息的大小與當前訊息佇列中的位元組數之和超過了訊息佇列的總容量;
-
當前訊息佇列的訊息數(單位"個")不小於訊息佇列的總容量(單位"位元組數"),此時,雖然訊息佇列中的訊息數目很多,但基本上都只有一個位元組。
msgsnd()解除阻塞的條件有三個:
-
不滿足上述兩個條件,即訊息佇列中有容納該訊息的空間;
-
msqid代表的訊息佇列被刪除;
-
呼叫msgsnd()的程序被訊號中斷;
呼叫返回:成功返回0,否則返回-1。
4)int msgctl(int msqid, int cmd, struct msqid_ds *buf);
該系統呼叫對由msqid標識的訊息佇列執行cmd操作,共有三種cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。
-
IPC_STAT:該命令用來獲取訊息佇列資訊,返回的資訊存貯在buf指向的msqid結構中;
-
IPC_SET:該命令用來設定訊息佇列的屬性,要設定的屬性儲存在buf指向的msqid結構中;可設定屬性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同時,也影響msg_ctime成員。
-
IPC_RMID:刪除msqid標識的訊息佇列;
呼叫返回:成功返回0,否則返回-1。
程式碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#define MSG_R 0400
#define MSG_W 0200
#define SVMSG_MODE (MSG_R | MSG_W | MSG_R >>3 | MSG_R >>6)
struct msgbuf
{
long mtype;
char mtext[1];
};
void system_v_test()
{
int msqid;
struct msqid_ds info;
struct msgbuf buf;
msqid=msgget(IPC_PRIVATE,SVMSG_MODE | IPC_CREAT);
buf.mtype=1;
buf.mtext[0]=1;
msgsnd(msqid,&buf,1,0);
msgctl(msqid,IPC_STAT,&info);
printf("read-write:%3o,cbytes=%lu,qnum=%lu,qbytes=%lu\n",info.msg_perm.mode & 0777,(ulong)info.msg_cbytes,(ulong)info.msg_qnum,(ulong)info.msg_qbytes);
msgctl(msqid,IPC_RMID,NULL);
}
執行結果: