訊息佇列提供了一種在兩個不相關的進程之間傳遞資料的相當簡單且有效方法。與具名管道相比,訊息佇列的優勢在於,它獨立於發送和接收進程而存在,這消除了在同步具名管道的開啟與關閉的可能產生的一些困難。
Linux系統有兩個宏定義MSGMAX和MSGMNB,它們以位元組為單位分別定義了一條訊息的最大長度和一個隊列的最大長度。
#include<sys/msg.h>
int msgctl(int msgid , int cmd, struct msqid_ds *buf);
int msgget(key_t key , int msgflg);
int msgrcv(int msqid , void *msg_ptr , size_t msg_sz , long int msgtype , int msgflg);
int msgsnd(int msqid , const void *msg_ptr , size_t msg_sz , int msgflg);
1.msgget函數
我們用msgget函數來建立與訪問一個訊息佇列。
int msgget(key_t key , int msgflg);
第一個參數可以任意指定一個key_t類型的變數。第二個參數msgflg由9個許可權標誌組成。
成功時msgget函數返回一個正整數,即隊列標識符,失敗時返回-1.
2.msgsnd函數
msgsnd函數用來把訊息添加到訊息佇列中
int msgsnd(int msqid , const void *msg_ptr , size_t msg_sz , int msgflg);
訊息的結構收到兩方面的約束,首先,它的長度必須小於系統規定的上限,其次,它必須以一個長整型成員變數開始,接收函數將用這個成員變數來確定訊息的類型。
當使用訊息時,最好把訊息結構定義為下面這個樣子:
struct my_message
{
long int mesage_type;
/*你想要發送的資料*/
第一個參數msqid是由msgget函數返回的訊息佇列標識符。
第二個參數msg_ptr是一個指向準備發送訊息的指標,訊息必須像剛才說的那樣以一個長整型成員變數開始。
第三個參數msg_sz是msg_ptr指向的訊息的長度。這個長度不能包括長整型訊息類型成員變數的長度。
第四個參數msgflg控制在當前訊息佇列滿或者隊列訊息到達系統範圍的限制時將要發生的事情。
3.msgrcv函數
msgrcv函數從一個訊息佇列中擷取訊息:
int msgrcv(int msqid , void *msg_ptr , size_t msg_sz , long int msgtype , int msgflg);
第一個參數是由msgget函數返回的訊息佇列標識符。
第二個參數是一個指向準備接受訊息的指標,訊息必須像前面msgsnd函數中介紹的那樣以一個長整型成員變數開始。
第三個參數msg_sz是msg_ptr指向的訊息的長度,它不包括長整型訊息類型成員變數的程度。
第四個參數msgtype是一個長整數,它可以實現一種簡單形式的接收優先順序。如果msgtype的值為0,就擷取訊息佇列中第一個可用的訊息。如果它的值大於0,將擷取具有相同訊息類型的第一個訊息。如果它的取值小於0,就把msgtype設定為-n。
第五個參數msgflg用於控制訊息隊列中沒有相應類型的訊息可以接收時,將要發生的事情。
4.msgctl函數
最後一個訊息佇列函數是msgctl,它的作用與共用記憶體的控制函數非常相識。
int msgctl(int msgid , int cmd, struct msqid_ds *buf);
msqid_ds結構至少包含以下成員:
struct msqid_ds
{
uid_t msg_perm.uid;
uid_t msg_perm.gid;
mode_t msg_perm.mode;
}
第一個參數msqid是由msgget函數返回的訊息佇列的標識符。
第二個參數command是將要採取的動作,它可以取三個值
命令
說明
IPC_STAT
把msqid_ds結構中的資料設定為訊息佇列的當前值
IPC_SET
如果進程有足夠的許可權,就把訊息佇列的當前關聯值設定為msqid_ds結構中給出的值
IPC_RMID
刪除訊息佇列。
函數在成員共返回0,失敗時返回-1.
/* Here's the receiver program. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <sys/msg.h>struct my_msg_st { long int my_msg_type; char some_text[BUFSIZ];};int main(){ int running = 1; int msgid; struct my_msg_st some_data; long int msg_to_receive = 0;/* First, we set up the message queue. */ msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if (msgid == -1) { fprintf(stderr, "msgget failed with error: %d\n", errno); exit(EXIT_FAILURE); }/* Then the messages are retrieved from the queue, until an end message is encountered. Lastly, the message queue is deleted. */ while(running) { if (msgrcv(msgid, (void *)&some_data, BUFSIZ, msg_to_receive, 0) == -1) { fprintf(stderr, "msgrcv failed with error: %d\n", errno); exit(EXIT_FAILURE); } printf("You wrote: %s", some_data.some_text); if (strncmp(some_data.some_text, "end", 3) == 0) { running = 0; } } if (msgctl(msgid, IPC_RMID, 0) == -1) { fprintf(stderr, "msgctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS);}
/* The sender program is very similar to msg1.c. In the main set up, delete the msg_to_receive declaration and replace it with buffer[BUFSIZ], remove the message queue delete and make the following changes to the running loop. We now have a call to msgsnd to send the entered text to the queue. */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <sys/msg.h>#define MAX_TEXT 512struct my_msg_st { long int my_msg_type; char some_text[MAX_TEXT];};int main(){ int running = 1; struct my_msg_st some_data; int msgid; char buffer[BUFSIZ]; msgid = msgget((key_t)1234, 0666 | IPC_CREAT); if (msgid == -1) { fprintf(stderr, "msgget failed with error: %d\n", errno); exit(EXIT_FAILURE); } while(running) { printf("Enter some text: "); fgets(buffer, BUFSIZ, stdin); some_data.my_msg_type = 1; strcpy(some_data.some_text, buffer); if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) { fprintf(stderr, "msgsnd failed\n"); exit(EXIT_FAILURE); } if (strncmp(buffer, "end", 3) == 0) { running = 0; } } exit(EXIT_SUCCESS);}