什么是消息隊列弥咪?
假設你是一個快遞員,你需要將貨物從一個倉庫運到另一個倉庫籍滴。但是你發(fā)現(xiàn)自己的時間不夠用酪夷,需要另外請一個人來幫忙。那么孽惰,你們之間如何進行協(xié)作呢?
一種方式是直接將貨物全部交給對方鸥印,但這樣存在風險:對方可能會出現(xiàn)問題勋功,導致貨物丟失或損壞。
而另一種更安全的方式是库说,你將貨物分批發(fā)送給對方狂鞋,對方再按照你的要求逐批接收貨物。這種方式類似于消息隊列的通信方式潜的。
在 Linux 系統(tǒng)中骚揍,消息隊列是一種 IPC(進程間通信)機制,用于實現(xiàn)不同進程之間的通信啰挪。
簡單地說信不,消息隊列是一個消息的鏈表,消息發(fā)送方將消息發(fā)送到消息隊列中亡呵,消息接收方從隊列中讀取消息抽活。
消息隊列的優(yōu)點和缺點
與其他 IPC 機制相比,消息隊列有以下優(yōu)點:
- 通過消息隊列可以實現(xiàn)異步通信锰什。
- 消息隊列可以存儲多個消息下硕,接收方可以按順序逐個讀取消息。
- 消息隊列的消息長度可以很長汁胆。
但是梭姓,消息隊列也有以下缺點:
- 消息隊列的消息長度有限制,一般不能超過系統(tǒng)限制的最大值嫩码。
- 消息隊列需要調(diào)用特殊的系統(tǒng)調(diào)用來讀寫消息誉尖,開銷較大。
消息隊列的創(chuàng)建和使用方法
在Linux中谢谦,可以通過以下系統(tǒng)調(diào)用函數(shù)來創(chuàng)建和使用消息隊列:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg); // 創(chuàng)建或打開消息隊列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); // 向消息隊列發(fā)送消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); // 從消息隊列接收消息
int msgctl(int msqid, int cmd, struct msqid_ds *buf); // 控制消息隊列
其中释牺,key
是用來唯一標識消息隊列的鍵值萝衩,msgflg
是創(chuàng)建消息隊列時的選項參數(shù)。在創(chuàng)建消息隊列時没咙,如果該鍵值已經(jīng)存在猩谊,則直接返回該消息隊列的標識符;如果不存在祭刚,則創(chuàng)建一個新的消息隊列牌捷,并返回該消息隊列的標識符。
在使用消息隊列時涡驮,msgsnd
函數(shù)用于向消息隊列中發(fā)送消息暗甥,msgrcv
函數(shù)用于從消息隊列中接收消息,msgctl
函數(shù)用于對消息隊列進行控制捉捅,比如刪除消息隊列等撤防。
消息隊列的發(fā)送和接收示例
下面我們來看一個簡單的示例,展示如何使用消息隊列進行進程間通信棒口。
假設有兩個進程寄月,一個發(fā)送進程和一個接收進程,它們之間需要傳遞一些數(shù)據(jù)无牵。我們通過消息隊列來實現(xiàn)進程間通信漾肮。
首先,我們需要創(chuàng)建一個消息隊列茎毁,然后讓發(fā)送進程向消息隊列中發(fā)送一條消息克懊,接收進程從消息隊列中接收該消息,并進行處理七蜘。
創(chuàng)建消息隊列
我們首先需要創(chuàng)建一個消息隊列谭溉。可以使用msgget
函數(shù)來創(chuàng)建消息隊列崔梗。以下是創(chuàng)建消息隊列的示例代碼:
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
key_t key = ftok("/tmp", 'a'); // 創(chuàng)建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創(chuàng)建消息隊列
if (msgid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
printf("消息隊列創(chuàng)建成功夜只,msgid=%d\n", msgid);
return 0;
}
在上面的代碼中,我們使用ftok
函數(shù)創(chuàng)建一個唯一的key蒜魄,這個key將作為消息隊列的標識符扔亥。然后,我們使用msgget
函數(shù)創(chuàng)建消息隊列谈为。如果創(chuàng)建成功旅挤,msgget
函數(shù)將返回一個消息隊列ID(msgid),否則將返回-1伞鲫。在本例中粘茄,如果創(chuàng)建消息隊列失敗,我們將輸出錯誤消息并退出程序。
發(fā)送消息
接下來柒瓣,我們將使用msgsnd
函數(shù)向消息隊列發(fā)送一些消息儒搭。以下是一個發(fā)送消息的示例代碼:
// sendmsg.c
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
long type;
char text[100];
} message_t;
int main()
{
key_t key = ftok("/tmp", 'a'); // 創(chuàng)建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創(chuàng)建消息隊列
if (msgid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
message_t message;
message.type = 1;
strcpy(message.text, "Hello, World!");
int result = msgsnd(msgid, &message, sizeof(message.text), 0);
if (result == -1) {
perror("msgsnd");
exit(EXIT_FAILURE);
}
printf("消息發(fā)送成功,text=%s\n", message.text);
return 0;
}
在上面的代碼中芙贫,我們定義了一個message_t
結(jié)構(gòu)體搂鲫,它包含一個長整型變量和一個字符串數(shù)組。長整型變量將用于指定消息類型磺平,而字符串數(shù)組將包含消息正文魂仍。然后,我們使用msgsnd
函數(shù)將消息發(fā)送到隊列拣挪。在本例中擦酌,我們發(fā)送的消息類型為1,消息正文為"Hello, World!"菠劝。
接收消息
最后赊舶,我們將使用msgrcv
函數(shù)從消息隊列接收我們之前發(fā)送的消息。以下是一個接收消息的示例代碼:
// rsvmsg.c
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
long type;
char text[100];
} message_t;
int main()
{
key_t key = ftok("/tmp", 'a'); // 創(chuàng)建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創(chuàng)建消息隊列
if (msgid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
message_t message;
int result = msgrcv(msgid, &message, sizeof(message.text), 1, 0);
if (result == -1) {
perror("msgrcv");
exit(EXIT_FAILURE);
}
printf("消息接收成功赶诊,text=%s\n", message.text);
return 0;
}
效果演示
編譯上面的sendmsg.c 和 rsvmsg.c文件锯岖,得到一個兩個程序:sendmsg和rsvmsg。
- 先運行sendmsg甫何,后運行rsvmsg
[wayne@wayne:~] ./sendmsg
消息發(fā)送成功,text=Hello, World!
[wayne@wayne:~] ./rsvmsg
消息接收成功遇伞,text=Hello, World!
- 先運行rsvmsg辙喂,后運行sendmsg
[wayne@wayne:~] ./rsvmsg
此時rsvmsg會阻塞在這里,等待消息
[wayne@wayne:~] ./sendmsg
消息發(fā)送成功鸠珠,text=Hello, World!
sendmsg發(fā)送消息后巍耗,rsvmsg進程,收到消息渐排,打印消息
消息接收成功炬太,text=Hello, World!
小結(jié)
總的來說,Linux 消息隊列是一種高效的進程間通信機制驯耻,它可以在多個進程之間共享亲族,允許進程異步地發(fā)送和接收消息。
以上可缚,如果覺得對你有幫助霎迫,點個贊再走吧,這樣@知微之見也有更新下去的動力帘靡!
也歡迎私信我知给,一起交流!