對訊息佇列的操作無非有下面三種類型:
1、 開啟或建立訊息佇列
訊息佇列的核心持久性要求每個訊息佇列都在系統範圍內對應唯一的索引值,所以,要獲得一個訊息佇列的描述字,只需提供該訊息佇列的索引值即可;
註:訊息佇列描述字是由在系統範圍內唯一的索引值產生的,而索引值可以看作對應系統內的一條路經。
2、 讀寫操作
訊息讀寫操作非常簡單,對開發人員來說,每個訊息都類似如下的資料結構:
struct msgbuf{long mtype;char mtext[1];};
|
mtype成員代表訊息類型,從訊息佇列中讀取訊息的一個重要依據就是訊息的類型;mtext是訊息內容,當然長度不一定為1。因此,對於發送訊息來說,首先預置一個msgbuf緩衝區並寫入訊息類型和內容,調用相應的發送函數即可;對讀取訊息來說,首先分配這樣一個msgbuf緩衝區,然後把訊息讀入該緩衝區即可。
3、 獲得或設定訊息佇列屬性:
訊息佇列的資訊基本上都儲存在訊息佇列頭中,因此,可以分配一個類似於訊息佇列頭的結構(struct msqid_ds,見附錄 2),來返回訊息佇列的屬性;同樣可以設定該資料結構。
訊息佇列API
1、檔案名稱到索引值
#include <sys/types.h>#include <sys/ipc.h>key_t ftok (char*pathname, char proj);
|
它返回與路徑pathname相對應的一個索引值。該函數不直接對訊息佇列操作,但在調用ipc(MSGGET,…)或msgget()來獲得訊息佇列描述字前,往往要調用該函數。典型的調用代碼是:
key=ftok(path_ptr, 'a'); ipc_id=ipc(MSGGET, (int)key, flags,0,NULL,0); …
|
2.系統V訊息佇列API
系統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。
----------------------------------------------------------------------------------------------------------------------
/*msgserver.c*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#define MSG_FILE "msgserver.c"
#define BUFFER 255
#define PERM S_IRUSR|S_IWUSR
/* 服務端建立的訊息佇列最後沒有刪除,我們要使用ipcrm命令來刪除的 */
/* ipcrm -q <msqid> */
struct msgtype {
long mtype;
char buffer[BUFFER+1];
};
int main()
{
struct msgtype msg;
key_t key;
int msgid;
if((key=ftok(MSG_FILE,'a'))==-1)
{
fprintf(stderr,"Creat Key Error:%s/n", strerror(errno));
exit(1);
}
if((msgid=msgget(key, PERM|IPC_CREAT|IPC_EXCL))==-1)
{
fprintf(stderr, "Creat Message Error:%s/n", strerror(errno));
exit(1);
}
printf("msqid = %d/n", msgid);
while(1)
{
msgrcv(msgid, &msg, sizeof(struct msgtype), 1, 0);
fprintf(stderr,"Server Receive:%s/n", msg.buffer);
msg.mtype = 2;
msgsnd(msgid, &msg, sizeof(struct msgtype), 0);
}
exit(0);
}
/* msgclient.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#define MSG_FILE "msgserver.c"
#define BUFFER 255
#define PERM S_IRUSR|S_IWUSR
struct msgtype {
long mtype;
char buffer[BUFFER+1];
};
int main(int argc, char **argv)
{
struct msgtype msg;
key_t key;
int msgid;
if(argc != 2)
{
fprintf(stderr,"Usage:%s string/n", argv[0]);
exit(1);
}
if((key=ftok(MSG_FILE,'a'))==-1)
{
fprintf(stderr,"Creat Key Error:%s/n", strerror(errno));
exit(1);
}
if((msgid=msgget(key, PERM))==-1)
{
fprintf(stderr,"Creat Message Error:%s/n", strerror(errno));
exit(1);
}
msg.mtype = 1;
strncpy(msg.buffer, argv[1], BUFFER);
msgsnd(msgid, &msg, sizeof(struct msgtype), 0);
memset(&msg, '/0', sizeof(struct msgtype));
msgrcv(msgid, &msg, sizeof(struct msgtype), 2, 0);
fprintf(stderr, "Client receive:%s/n", msg.buffer);
exit(0);
}
http://blog.csdn.net/zhsp1029/article/details/2171462