原理說明:
消息隊列是內核地址空間中的內部鏈表,通過linux內核在各個進程之間傳遞內容,消息順序地發送到消息隊列中,並且以幾種不同的方式
從隊列中獲取,每個消息隊列可以用IPC標識符唯一的進行標識,內核中的消息隊列是通過IPC的標識符來區別的,不同的消息隊列之間是
相互獨立的,每個消息隊列中的消息又構成一個獨立的鏈表.
消息隊列中的數據結構
1、消息緩衝結構
向消息隊列發送消息時,必須組成合理的數據結構。Linux系統定義了一個模版數據結構msgbuf:
#include<linux/msg.h>
struct msgbuf{
long type;
char mtext[1];
}
其中type表示消息的類型,以正數表示。mtext是該消息的數據,並不一定就是char 類型,任意類型都可以的。
2、msqid_ds內核數據結構。
struct msqid_ds{
struct ipc_perm msg_perm;
time_t msg_stime;
time_t msg_rtime;
time_t msg_ctime;
unsigned long _msg_cbuyes;
..........
};
Linux內核中,每個消息隊列都維護一個結構體,此結構體保存着消息隊列當前狀態信息,該結構體在頭文件linux/msg.h中定義。
3、ipc_perm內核數據結構
struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
.......
};
結構體ipc_perm保存着消息隊列的一些重要的信息,比如說消息隊列關聯的鍵值,消息隊列的用戶id組id等。它定義在頭文件linux/ipc.h中
Linux的消息隊列(queue)實質上是一個鏈表, 它有消息隊列標識符(queue ID). msgget創建一個新隊列或打開一個存在的隊列; msgsnd向隊列末端
添加一條新消息; msgrcv從隊列中取消息, 取消息是不一定遵循先進先出的, 也可以按消息的類型字段取消息.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
參數key是一個鍵值,由ftok獲得;msgflg參數是一些標誌位。該調用返回與健值key相對應的消息隊列描述字,如果沒有消息隊列與健值key相對應,
並且msgflg中包含了IPC_CREAT標誌位或者key參數爲IPC_PRIVATE,那麼該調用將創建一個新的消息隊列。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
該系統調用從msgid代表的消息隊列中讀取一個消息,並把消息存儲在msgp指向的msgbuf結構中。
msqid爲消息隊列描述字;消息返回後存儲在msgp指向的地址,msgsz指定msgbuf的mtext成員的長度(即消息內容的長度),msgtyp爲請求讀
取的消息類型,成功返回讀出消息的實際字節數,否則返回-1。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
向msgid代表的消息隊列發送一個消息,即將發送的消息存儲在msgp指向的msgbuf結構中,消息的大小由msgze指定。
對發送消息來說,有意義的msgflg標誌爲IPC_NOWAIT,指明在消息隊列沒有足夠空間容納要發送的消息時,msgsnd是否等待。成功返回0,否則
返回-1。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
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標識的消息隊列;
read.c
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <stdio.h>
typedef struct msg_st
{
long int msg_type;
char text[BUFSIZ];
} MSG_ST ;
int main()
{
int running = 1;
int msgid = -1;
MSG_ST data;
long int msgtype = 2;
msgid = msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid == -1)
{
puts("msgget fail \n");
exit(EXIT_FAILURE);
}
while(running)
{
if(msgrcv(msgid,(void *)&data,BUFSIZ,msgtype,0) == -1)
{
puts("msgrcv fail \n");
exit(EXIT_FAILURE);
}
printf("rcv data type %d\n",data.msg_type);
printf("rcv data text %s\n",data.text);
if(strncmp(data.text,"end",3)==0)
running = 0;
}
if(msgctl(msgid,IPC_RMID,0)==-1)
{
printf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
write.c
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
typedef struct msg_st
{
long int msg_type;
char text[MAX_TEXT];
}MSG_ST;
int main()
{
int running = 1 ;
struct msg_st data;
char buffer[BUFSIZ];
int msgid = -1;
printf("bufsize size is %d\n",BUFSIZ);
printf("MAX_TEXT is %d\n",MAX_TEXT);
msgid = msgget((key_t)1234,0666 | IPC_CREAT);
if(msgid == -1)
{
puts("msgget fail !\n");
exit(EXIT_FAILURE);
}
while(running)
{
puts("input data");
fgets(buffer,BUFSIZ,stdin);
data.msg_type = 2;
strcpy(data.text,buffer);
if(msgsnd(msgid,(void *)&data,MAX_TEXT,0) == -1)
{
puts("msgsnd fail !\n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer,"end",3)==0)
running = 0;
sleep(1);
}
puts("exit success\n");
exit(EXIT_FAILURE);
}