1.概述
消息隊列是一種通過鏈表結構組織的一組消息。與其他兩種進程間通信(共享內存、信號量)相同,都存放在內核中。多個進程通過消息隊列的標識符對消息數據進行傳送,實現進程間通信。
2.消息隊列的相關操作
使用消息隊列實現進程間通信,需要首先用msgget()函數創建一個消息隊列,然後調用msgsnd()函數向該消息隊列中發送指定的消息,通過msgrcv()函數接收該消息,最後調用msgctl()函數對消息隊列進行指定的控制操作,這樣一個使用消息隊列實現進程間通信就實現了。
2.1 msgget()函數
該函數用於創建一個新的消息隊列或打開一個已經存在的消息隊列,該函數的定義爲:
#include <sys/tyoes.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
參數說明:
key: 表示所創建的消息隊列的名字。
msgflg: 用於設置消息隊列的訪問權限,也可以表示該函數的操作類型。
如果該函數調用成功,返回值爲與參數key相關聯的標識符;如果調用失敗,則返回-1.
注意:創建消息隊列的函數msgget()中參數所遵循的原則與創建共享內存的shmget()函數類似。
2.2 msgsnd()函數
msgsnd()函數用於向消息隊列中發送消息,該函數定義如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg);
msqid: 將信息發送到消息隊列的標識符。
msgp: 指向要發送的消息數據。
msgsz: 以字節數表示的消息數據的長度。
msgflg: 消息隊列滿時的處理方法,該參數可以是0或IPC_NOWAIT.
該函數調用成功返回0;失敗返回-1.
要發送的數據存放在msgbuf結構體中,使用msgp指針指向該類型引用消息數據的內容和消息的類型。msgbuf結構體定義如下:
struct msgbuf
{
long mtype; /*消息類型,以大於0的整數表示*/
char mtext[1]; /*消息內容*/
};
如果消息隊列中有足夠的空間,msgsnd()函數會立即返回,並實現發送消息到msgp指定的消息隊列中; 如果消息隊列已滿的話,msgflg參數沒有設置IPC_NOWAIT值,則msgsnd()將會阻塞;如果設置了IPC_NOWAIT值,則msgsnd()函數調用失敗,並返回-1,直到消息隊列中有空間時,函數才返回0.
2.3 msgrcv()函數
msgrcv()函數用於接收消息隊列中的消息數據,該函數定義如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void* msgp, size_t msgsz, long msgtyp, int msgflg);
msqid: 從msqid標識符所代表得消息隊列中接收消息。
msgp: 指向存放消息數據的內存空間。
msgsz: 以字節數表示的消息數據的長度。
msgtyp: 讀取的消息數據的類型。
msgflg: 對讀取的消息數據不滿足情況的處理。
該函數調用成功時,返回0;如果調用失敗,返回-1.
2.4 msgctl()函數
該函數主要實現對消息隊列的控制操作,該函數定義如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct maqid_ds* buf);
msgctl()函數實現對msqid標識符所指向的消息隊列進行控制,控制內容取決於參數cmd的取值。
命令 | 說明 |
---|---|
IPC_STAT | 把msqid_ds結構中的數據設置爲消息隊列的當前關聯值 |
IPC_SET | 在進程有足夠權限的前提下,把消息隊列的當前關聯值設置爲msqid_ds數據結構中給出的值 |
IPC_RMID | 刪除消息隊列 |
3.消息隊列實現進程間通信
在Linux系統中,使用msgget()函數創建一個消息隊列,通過msgsnd()函數發送兩次消息,第一次發送消息內容爲:“hello Linux!”,第二次發送的消息爲"Goodbye!"。接下來調用msgrcv()函數接收消息,這樣就實現了一個消息隊列的進程間通信。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
key_t key;
int proj_id = 1;
int msqid;
char message1[] = {"Hello Linux!"};
char message2[] = {"Goodbye!"};
struct msgbuf
{
long msgtype; //消息類型
char msgtext[1024]; //消息內容
}snd, rcv;
key = ftok("/root/process/mq", proj_id);
if(key == -1)
{
perror("create key error!");
return 1;
}
if((msqid = msgget(key, IPC_CREAT|0666)) == -1)
{
printf("msgget error!\n");
exit(1);
}
snd.msgtype = 1;
sprintf(snd.msgtext, message1);
if(msgsnd(msqid, (struct msgbuf*) &snd, sizeof(message1)+1, 0) == -1)
{
printf("msgsnd error!\n");
exit(1);
}
snd.msgtype = 2;
sprintf(snd.msgtext,"%s", message2);
if(msgsnd(msqid,(struct msgbuf*)&snd, sizeof(message2)+1, 0) == -1)
{
printf("msgrcv error!\n");
exit(1);
}
if(msgrcv(msqid,(struct msgbuf*)& rcv, 80, 1, IPC_NOWAIT) == -1)
{
printf("msgrcv error!\n");
exit(1);
}
printf("the received message: %s\n", rcv.msgtext);
msgctl(msqid, IPC_RMID, 0); /*刪除新創建的消息隊列*/
exit(0);
}