Linux進程通信 | 消息隊列
什么是消息隊列?
假設你是一個快遞員,你需要將貨物從一個倉庫運到另一個倉庫。但是你發(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)建一個消息隊列??梢允褂?code>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ā)送和接收消息。
以上,如果覺得對你有幫助,點個贊再走吧,這樣@知微之見也有更新下去的動力!
也歡迎私信我,一起交流!

浙公網(wǎng)安備 33010602011771號