您好,登录后才能下订单哦!
# 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表示默认)
返回值:
- 成功:返回消息队列描述符
- 失败:返回(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
:缓冲区大小(必须≥队列的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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。