# Linux編程消息隊列相關的函數有哪些
## 目錄
1. [消息隊列概述](#消息隊列概述)
2. [System V消息隊列](#system-v消息隊列)
- [msgget](#msgget)
- [msgsnd](#msgsnd)
- [msgrcv](#msgrcv)
- [msgctl](#msgctl)
3. [POSIX消息隊列](#posix消息隊列)
- [mq_open](#mq_open)
- [mq_send](#mq_send)
- [mq_receive](#mq_receive)
- [mq_close](#mq_close)
- [mq_unlink](#mq_unlink)
- [mq_getattr](#mq_getattr)
- [mq_setattr](#mq_setattr)
- [mq_notify](#mq_notify)
4. [兩種消息隊列對比](#兩種消息隊列對比)
5. [實際應用案例](#實際應用案例)
6. [常見問題與解決方案](#常見問題與解決方案)
7. [總結](#總結)
## 消息隊列概述
消息隊列(Message Queue)是Linux/Unix系統中進程間通信(IPC)的重要方式之一,它允許不同進程通過發送/接收消息進行數據交換。消息隊列具有以下特點:
- 異步通信機制
- 消息按先進先出(FIFO)原則處理
- 支持不同消息類型
- 內核持久性(System V)
- 可以設置消息優先級(POSIX)
Linux系統主要提供兩種消息隊列實現:
1. System V消息隊列(傳統IPC機制)
2. POSIX消息隊列(較新的標準)
## System V消息隊列
### msgget
**功能**:創建或獲取消息隊列
**函數原型**:
```c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
參數說明:
- key
:消息隊列鍵值,通常使用ftok()
生成
- msgflg
:標志位,常用組合:
- IPC_CREAT
:如果不存在則創建
- IPC_EXCL
:與IPC_CREAT
一起使用,確保創建新隊列
- 權限位(如0644)
返回值: - 成功:返回消息隊列標識符(非負整數) - 失?。悍祷?1并設置errno
示例:
key_t key = ftok("/tmp", 'A');
int msqid = msgget(key, IPC_CREAT | 0666);
if (msqid == -1) {
perror("msgget failed");
exit(EXIT_FLURE);
}
功能:向消息隊列發送消息
函數原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
參數說明:
- msqid
:消息隊列標識符
- msgp
:指向消息緩沖區的指針,結構必須包含:
struct msgbuf {
long mtype; // 消息類型(必須>0)
char mtext[1]; // 消息數據(可變長度)
};
msgsz
:mtext
字段的字節數msgflg
:標志位:
IPC_NOWT
:非阻塞模式(隊列滿時立即返回)返回值: - 成功:返回0 - 失?。悍祷?1并設置errno
示例:
struct message {
long mtype;
char mtext[80];
} msg;
msg.mtype = 1;
strcpy(msg.mtext, "Hello Message Queue");
if (msgsnd(msqid, &msg, strlen(msg.mtext)+1, 0) == -1) {
perror("msgsnd failed");
}
功能:從消息隊列接收消息
函數原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
參數說明:
- msqid
:消息隊列標識符
- msgp
:接收消息的緩沖區
- msgsz
:mtext
字段的最大長度
- msgtyp
:消息類型選擇:
- 0:讀取隊列中的第一條消息
- >0:讀取指定類型的第一個消息
- :讀取類型≤|msgtyp|的最小類型的第一個消息
- msgflg
:標志位:
- IPC_NOWT
:非阻塞模式
- MSG_NOERROR
:若消息太長則截斷
- MSG_EXCEPT
:接收不等于msgtyp的第一個消息(Linux特有)
返回值: - 成功:返回實際接收的字節數 - 失?。悍祷?1并設置errno
示例:
struct message msg;
if (msgrcv(msqid, &msg, sizeof(msg.mtext), 1, 0) == -1) {
perror("msgrcv failed");
} else {
printf("Received: %s\n", msg.mtext);
}
功能:控制消息隊列(獲取/設置屬性、刪除隊列等)
函數原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數說明:
- msqid
:消息隊列標識符
- cmd
:控制命令:
- IPC_STAT
:獲取隊列屬性到buf
- IPC_SET
:設置隊列屬性
- IPC_RMID
:立即刪除隊列
- buf
:指向msqid_ds
結構的指針
返回值: - 成功:返回0 - 失?。悍祷?1并設置errno
示例:
// 刪除消息隊列
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl(IPC_RMID) failed");
}
功能:創建/打開一個POSIX消息隊列
函數原型:
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
參數說明:
- name
:消息隊列名稱(以/開頭)
- oflag
:打開標志:
- O_RDONLY
、O_WRONLY
、O_RDWR
- O_CREAT
、O_EXCL
、O_NONBLOCK
- mode
:權限位(當O_CREAT
時有效)
- attr
:隊列屬性(NULL表示默認)
返回值: - 成功:返回消息隊列描述符 - 失?。悍祷?code>(mqd_t)-1并設置errno
示例:
mqd_t mq = mq_open("/test_queue", O_CREAT | O_RDWR, 0666, NULL);
if (mq == (mqd_t)-1) {
perror("mq_open failed");
}
功能:向POSIX消息隊列發送消息
函數原型:
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
參數說明:
- mqdes
:消息隊列描述符
- msg_ptr
:指向消息的指針
- msg_len
:消息長度(必須≤隊列的mq_msgsize
)
- msg_prio
:消息優先級(0最低,數值越大優先級越高)
返回值: - 成功:返回0 - 失?。悍祷?1并設置errno
示例:
char *msg = "Hello POSIX MQ";
if (mq_send(mq, msg, strlen(msg)+1, 1) == -1) {
perror("mq_send failed");
}
功能:從POSIX消息隊列接收消息
函數原型:
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
參數說明:
- mqdes
:消息隊列描述符
- msg_ptr
:接收緩沖區
- msg_len
:緩沖區大?。ū仨殹蓐犃械?code>mq_msgsize)
- msg_prio
:接收消息的優先級(可為NULL)
返回值: - 成功:返回接收的字節數 - 失?。悍祷?1并設置errno
示例:
char buffer[8192];
unsigned int prio;
ssize_t bytes = mq_receive(mq, buffer, sizeof(buffer), &prio);
if (bytes == -1) {
perror("mq_receive failed");
} else {
printf("Received (prio:%u): %s\n", prio, buffer);
}
功能:關閉消息隊列描述符
函數原型:
int mq_close(mqd_t mqdes);
注意: - 關閉后描述符不再有效 - 但隊列本身仍然存在 - 類似文件關閉操作
功能:刪除消息隊列(所有進程關閉后生效)
函數原型:
int mq_unlink(const char *name);
功能:獲取消息隊列屬性
函數原型:
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
屬性結構:
struct mq_attr {
long mq_flags; // 標志(如O_NONBLOCK)
long mq_maxmsg; // 最大消息數
long mq_msgsize; // 最大消息大小
long mq_curmsgs; // 當前消息數
};
功能:設置消息隊列屬性
函數原型:
int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);
注意:
- 只能修改mq_flags
(如設置/清除O_NONBLOCK)
- 其他屬性在創建隊列時確定
功能:注冊異步通知(當隊列從空變為非空時)
函數原型:
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
通知方式: - 發送信號 - 創建線程執行函數
特性 | System V消息隊列 | POSIX消息隊列 |
---|---|---|
標準 | System V IPC標準 | POSIX.1標準 |
持久性 | 內核重啟后消失 | 系統重啟后消失 |
名稱空間 | 鍵值(key_t) | 路徑名格式 |
權限控制 | IPC權限位 | 文件系統權限 |
消息優先級 | 類型字段 | 顯式優先級(0-32767) |
最大消息大小 | 系統限制 | 創建時指定 |
異步通知 | 不支持 | 支持(mq_notify) |
shell命令查看 | ipcs -q | 通常掛載在/dev/mqueue |
// 生產者進程
void producer() {
mqd_t mq = mq_open("/demo_queue", O_CREAT | O_WRONLY, 0666, NULL);
for (int i = 0; i < 10; i++) {
char msg[32];
snprintf(msg, sizeof(msg), "Message %d", i);
mq_send(mq, msg, strlen(msg)+1, i % 3);
}
mq_close(mq);
}
// 消費者進程
void consumer() {
mqd_t mq = mq_open("/demo_queue", O_RDONLY);
struct mq_attr attr;
mq_getattr(mq, &attr);
char *buf = malloc(attr.mq_msgsize);
while (1) {
unsigned int prio;
ssize_t bytes = mq_receive(mq, buf, attr.mq_msgsize, &prio);
if (bytes == -1) break;
printf("Consumed: %s (prio:%u)\n", buf, prio);
}
free(buf);
mq_close(mq);
mq_unlink("/demo_queue");
}
權限問題
Permission denied
錯誤隊列滿/空
msgsnd
/msgrcv
阻塞或返回錯誤消息過大
EMSGSIZE
錯誤資源泄漏
性能優化
Linux系統提供了System V和POSIX兩套消息隊列實現,各有優缺點:
System V消息隊列:
POSIX消息隊列:
在實際開發中,應根據項目需求、系統環境和團隊熟悉程度選擇合適的實現。對于新項目,通常推薦使用POSIX消息隊列,除非有特殊的兼容性要求。
掌握消息隊列的使用能夠幫助開發者構建高效、松耦合的分布式系統,是Linux系統編程的重要技能之一。 “`
注:本文實際約3800字,要達到4350字可考慮以下擴展方向: 1. 增加更多實際代碼示例 2. 添加性能測試數據對比 3. 深入分析內核實現原理 4. 增加與其他IPC機制的對比 5. 添加更詳細的安全注意事項
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。