什麼是消息隊列? 假設你是一個快遞員,你需要將貨物從一個倉庫運到另一個倉庫。但是你發現自己的時間不夠用,需要另外請一個人來幫忙。那麼,你們之間如何進行協作呢? 一種方式是直接將貨物全部交給對方,但這樣存在風險:對方可能會出現問題,導致貨物丟失或損壞。 而另一種更安全的方式是,你將貨物分批發送給對方, ...
什麼是消息隊列?
假設你是一個快遞員,你需要將貨物從一個倉庫運到另一個倉庫。但是你發現自己的時間不夠用,需要另外請一個人來幫忙。那麼,你們之間如何進行協作呢?
一種方式是直接將貨物全部交給對方,但這樣存在風險:對方可能會出現問題,導致貨物丟失或損壞。
而另一種更安全的方式是,你將貨物分批發送給對方,對方再按照你的要求逐批接收貨物。這種方式類似於消息隊列的通信方式。
在 Linux 系統中,消息隊列是一種 IPC(進程間通信)機制,用於實現不同進程之間的通信。
簡單地說,消息隊列是一個消息的鏈表,消息發送方將消息發送到消息隊列中,消息接收方從隊列中讀取消息。
消息隊列的優點和缺點
與其他 IPC 機制相比,消息隊列有以下優點:
- 通過消息隊列可以實現非同步通信。
- 消息隊列可以存儲多個消息,接收方可以按順序逐個讀取消息。
- 消息隊列的消息長度可以很長。
但是,消息隊列也有以下缺點:
- 消息隊列的消息長度有限制,一般不能超過系統限制的最大值。
- 消息隊列需要調用特殊的系統調用來讀寫消息,開銷較大。
消息隊列的創建和使用方法
在Linux中,可以通過以下系統調用函數來創建和使用消息隊列:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg); // 創建或打開消息隊列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); // 向消息隊列發送消息
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
是創建消息隊列時的選項參數。在創建消息隊列時,如果該鍵值已經存在,則直接返回該消息隊列的標識符;如果不存在,則創建一個新的消息隊列,並返回該消息隊列的標識符。
在使用消息隊列時,msgsnd
函數用於向消息隊列中發送消息,msgrcv
函數用於從消息隊列中接收消息,msgctl
函數用於對消息隊列進行控制,比如刪除消息隊列等。
消息隊列的發送和接收示例
下麵我們來看一個簡單的示例,展示如何使用消息隊列進行進程間通信。
假設有兩個進程,一個發送進程和一個接收進程,它們之間需要傳遞一些數據。我們通過消息隊列來實現進程間通信。
首先,我們需要創建一個消息隊列,然後讓發送進程向消息隊列中發送一條消息,接收進程從消息隊列中接收該消息,併進行處理。
創建消息隊列
我們首先需要創建一個消息隊列。可以使用msgget
函數來創建消息隊列。以下是創建消息隊列的示例代碼:
#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
key_t key = ftok("/tmp", 'a'); // 創建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創建消息隊列
if (msgid == -1) {
perror("msgget");
exit(EXIT_FAILURE);
}
printf("消息隊列創建成功,msgid=%d\n", msgid);
return 0;
}
在上面的代碼中,我們使用ftok
函數創建一個唯一的key,這個key將作為消息隊列的標識符。然後,我們使用msgget
函數創建消息隊列。如果創建成功,msgget
函數將返回一個消息隊列ID(msgid),否則將返回-1。在本例中,如果創建消息隊列失敗,我們將輸出錯誤消息並退出程式。
發送消息
接下來,我們將使用msgsnd
函數向消息隊列發送一些消息。以下是一個發送消息的示例代碼:
// 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'); // 創建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創建消息隊列
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("消息發送成功,text=%s\n", message.text);
return 0;
}
在上面的代碼中,我們定義了一個message_t
結構體,它包含一個長整型變數和一個字元串數組。長整型變數將用於指定消息類型,而字元串數組將包含消息正文。然後,我們使用msgsnd
函數將消息發送到隊列。在本例中,我們發送的消息類型為1,消息正文為"Hello, World!"。
接收消息
最後,我們將使用msgrcv
函數從消息隊列接收我們之前發送的消息。以下是一個接收消息的示例代碼:
// 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'); // 創建一個唯一的key
int msgid = msgget(key, 0666 | IPC_CREAT); // 創建消息隊列
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
消息發送成功,text=Hello, World!
[wayne@wayne:~] ./rsvmsg
消息接收成功,text=Hello, World!
- 先運行rsvmsg,後運行sendmsg
[wayne@wayne:~] ./rsvmsg
此時rsvmsg會阻塞在這裡,等待消息
[wayne@wayne:~] ./sendmsg
消息發送成功,text=Hello, World!
sendmsg發送消息後,rsvmsg進程,收到消息,列印消息
消息接收成功,text=Hello, World!
小結
總的來說,Linux 消息隊列是一種高效的進程間通信機制,它可以在多個進程之間共用,允許進程非同步地發送和接收消息。
以上,如果覺得對你有幫助,點個贊再走吧,這樣@知微之見也有更新下去的動力!
也歡迎私信我,一起交流!