Linux编程消息队列相关的函数有哪些

发布时间:2022-01-27 14:38:41 作者:iii
来源:亿速云 阅读:145
# 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);
}

msgsnd

功能:向消息队列发送消息

函数原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数说明: - msqid:消息队列标识符 - msgp:指向消息缓冲区的指针,结构必须包含:

  struct msgbuf {
      long mtype;     // 消息类型(必须>0)
      char mtext[1];  // 消息数据(可变长度)
  };

返回值: - 成功:返回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");
}

msgrcv

功能:从消息队列接收消息

函数原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

参数说明: - msqid:消息队列标识符 - msgp:接收消息的缓冲区 - msgszmtext字段的最大长度 - 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);
}

msgctl

功能:控制消息队列(获取/设置属性、删除队列等)

函数原型

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消息队列

mq_open

功能:创建/打开一个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_RDONLYO_WRONLYO_RDWR - O_CREATO_EXCLO_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");
}

mq_send

功能:向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");
}

mq_receive

功能:从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);
}

mq_close

功能:关闭消息队列描述符

函数原型

int mq_close(mqd_t mqdes);

注意: - 关闭后描述符不再有效 - 但队列本身仍然存在 - 类似文件关闭操作

mq_unlink

功能:删除消息队列(所有进程关闭后生效)

函数原型

int mq_unlink(const char *name);

mq_getattr

功能:获取消息队列属性

函数原型

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;  // 当前消息数
};

mq_setattr

功能:设置消息队列属性

函数原型

int mq_setattr(mqd_t mqdes, const struct mq_attr *newattr, struct mq_attr *oldattr);

注意: - 只能修改mq_flags(如设置/清除O_NONBLOCK) - 其他属性在创建队列时确定

mq_notify

功能:注册异步通知(当队列从空变为非空时)

函数原型

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");
}

常见问题与解决方案

  1. 权限问题

    • 现象:Permission denied错误
    • 解决:检查进程用户权限和队列权限设置
  2. 队列满/空

    • 现象:msgsnd/msgrcv阻塞或返回错误
    • 解决:合理设置队列容量或使用非阻塞模式
  3. 消息过大

    • 现象:EMSGSIZE错误
    • 解决:检查消息大小限制,必要时分割消息
  4. 资源泄漏

    • 现象:系统消息队列数量达到上限
    • 解决:确保不再使用的队列被正确删除
  5. 性能优化

    • 批量处理消息
    • 合理设置消息大小
    • 考虑使用共享内存传输大数据

总结

Linux系统提供了System V和POSIX两套消息队列实现,各有优缺点:

在实际开发中,应根据项目需求、系统环境和团队熟悉程度选择合适的实现。对于新项目,通常推荐使用POSIX消息队列,除非有特殊的兼容性要求。

掌握消息队列的使用能够帮助开发者构建高效、松耦合的分布式系统,是Linux系统编程的重要技能之一。 “`

注:本文实际约3800字,要达到4350字可考虑以下扩展方向: 1. 增加更多实际代码示例 2. 添加性能测试数据对比 3. 深入分析内核实现原理 4. 增加与其他IPC机制的对比 5. 添加更详细的安全注意事项

推荐阅读:
  1. Unix/Linux编程之ftok函数用法
  2. Python中与迭代相关的函数有哪些

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux

上一篇:Linux进程共享内存的方法是什么

下一篇:jstat命令怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》