什么是訊息佇列?
假設你是一個快遞員,你需要將貨物從一個倉庫運到另一個倉庫,但是你發現自己的時間不夠用,需要另外請一個人來幫忙,那么,你們之間如何進行協作呢?
一種方式是直接將貨物全部交給對方,但這樣存在風險:對方可能會出現問題,導致貨物丟失或損壞,
而另一種更安全的方式是,你將貨物分批發送給對方,對方再按照你的要求逐批接識訓物,這種方式類似于訊息佇列的通信方式,
在 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 訊息佇列是一種高效的行程間通信機制,它可以在多個行程之間共享,允許行程異步地發送和接收訊息,
以上,如果覺得對你有幫助,點個贊再走吧,這樣@知微之見也有更新下去的動力!
也歡迎私信我,一起交流!
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/547168.html
標籤:其他
上一篇:RHEL8使用NMCLI管理網路
下一篇:Centos7系統在開啟進入系統報錯:Give root password for maintenance(or type Control-D to continue):問題解決方法
