進程間通信(IPC):消息隊列
消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標識。
特點
(1)消息隊列是消息的鏈表,具有特定的格式,存放在內存中並由消息隊列標識符標識.
(2)消息隊列允許一個或多個進程向它寫入與讀取消息.
(3)管道和消息隊列的通信數據都是先進先出的原則。
(4)消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取.比FIFO更有優勢。
(5)消息隊列克服了信號承載信息量少,管道只能承載無格式字 節流以及緩衝區大小受限等缺。
(6)目前主要有兩種類型的消息隊列:POSIX消息隊列以及System V消息隊列,系統V消息隊列目前被大量使用。系統V消息隊列是隨內核持續的,只有在內核重起或者人工刪除時,該消息隊列纔會被刪除。
Linux提供了一組消息隊列函數讓我們使用消息隊列,消息隊列函數定義如下:
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
/*
函數msgget用於得到一個已存在的消息隊列標識符或創建一個消息隊列對象。
參數key表示消息隊列的鍵值,用於標識一個消息隊列,函數將它與已有的消息隊列對象的鍵值比較,以此來判斷消息隊列對象是否已經創建。key_t是一個32位整型;參數mflag表示創建或訪問消息隊列的具體方式。
如果函數執行成功返回一個正數作爲消息隊列標識符,失敗返回-1,通過errno可以獲取錯誤碼。
*/
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
/*
函數msgctl用於獲取和設置消息隊列的屬性。
參數msqid是消息隊列標識符;cmd表示要對消息隊列進行的操作;buf指向消息隊列管理結構體msqid_ds。
如果函數執行成功返回0,失敗返回-1,通過errno可以獲取錯誤碼。
*/
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflag);
/*
函數msgsnd用來將消息送入消息隊列。
參數msqid是消息隊列標識符;msg_ptr表示消息緩衝區指針,用來暫時存儲要發送的消息;msg_sz是要發送信息的長度(字節數);msgflag是控制函數行爲的標誌。
如果函數執行成功返回0,失敗返回-1,通過errno可以獲取錯誤碼。
*/
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflag);
/*
函數msgrcv用於從消息隊列中讀出一條新消息。
參數msqid是消息隊列標識符;msg_ptr指向要讀出消息的緩衝區;msg_sz是消息數據的長度(字節數);msgtype表示從消息隊列內讀取的消息形態,0代表消息隊列中的所有消息都會被讀取;msgflag是控制函數行爲的標誌。
如果函數執行成功返回讀取的字節數,失敗返回-1,通過errno可以獲取錯誤碼。
*/
消息隊列的發送與接收
接收:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.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; // 讀取消息隊列中的全部消息
// 創建消息隊列
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if(msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
// 接收消息隊列中的消息直到遇到一個end消息。最後,消息隊列被刪除
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 failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
發送:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st
{
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
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 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;
}
}
exit(EXIT_SUCCESS);
}