linux应用 进程间通信之消息队列(POSIX)

1、前言

1.1 定义

POSIX消息队列是Linux中一种进程间通信机制,允许进程通过发送和接收消息来交换数据。这些消息在队列中按优先级顺序存储和传递。

1.2 应用场景

  • 当多个进程需要共享或交换数据时。
  • 实现进程间的解耦和异步通信。
  • 作为缓冲区,处理速度不同的进程之间的数据传输。

1.3 优缺点

1.3.1 优点
  • 灵活,支持多种数据类型和优先级。
  • 可靠,消息持久化且不会因发送者崩溃而丢失。
  • 高效,支持大量数据的传输和并行处理。
1.3.2 缺点
  • 相比管道和信号,API更复杂。
  • 可能存在数据复制的开销。
  • 需要管理访问权限以确保安全性。

2、常用接口

2.1 mq_open()

打开一个已存在的消息队列,或创建一个新的消息队列。

mqd_t mq_open(const char *name, int oflag, ...);

入参:

  • name:消息队列的名称。
  • oflag:打开或创建队列时的选项标志,可以是以下一个或多个选项的按位或:
    • O_RDONLY:以只读方式打开消息队列。
    • O_WRONLY:以只写方式打开消息队列。
    • O_CREAT:如果指定的消息队列不存在,则创建它。
    • O_EXCL:与O_CREAT一起使用,如果消息队列已存在,则返回错误。
  • 如果使用了O_CREAT标志,还需要提供两个额外的参数:mode_t modestruct mq_attr *attrmode指定新队列的权限,attr指定队列的属性;否则,这两个参数可以省略。

返回值:

  • 成功时返回一个消息队列描述符(mqd_t类型),失败时返回-1并设置errno

2.2 mq_send() 和 mq_timedsend()

向指定的消息队列发送消息。

int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout);

入参:

  • mqdes: 消息队列描述符,通过 mq_open 函数打开消息队列后获得。
  • msg_ptr: 指向要发送的消息的指针。
  • msg_len: 要发送的消息的长度。
  • msg_prio: 消息的优先级。
  • abs_timeout: 指定发送消息的超时时间,为绝对时间,使用 struct timespec 结构表示。

返回值:

  • 成功时,返回0表示消息成功发送。
  • 失败时,返回-1,并设置 errno 以指示错误类型。

2.3 mq_receive() 和 mq_timedreceive()

从指定的消息队列接收消息。

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abs_timeout);

入参:

  • mqdes:消息队列描述符。
  • msg_ptr:指向接收消息的缓冲区的指针。
  • msg_len:接收消息的最大长度。
  • msg_prio:指向存储接收消息优先级的变量的指针。
  • abs_timeout(仅mq_timedreceive()):指向timespec结构的指针,指定了接收操作的绝对超时时间;如果为NULL,则不设置超时。

返回值:

  • 成功时返回接收到的消息长度,失败时返回-1并设置errno

2.4 mq_close()

关闭一个打开的消息队列描述符。

int mq_close(mqd_t mqdes);

入参:

  • mqdes:消息队列描述符。

返回值:

  • 成功时返回0,失败时返回-1并设置errno

2.5 mq_unlink()

删除一个命名的消息队列。

int mq_unlink(const char *name);

入参:

  • name:要删除的消息队列的名称。

返回值:
成功时返回0,失败时返回-1并设置errno

2.6 mq_getattr() 和 mq_setattr()

mq_getattr()获取消息队列的属性;mq_setattr()设置消息队列的属性,并可以选择性地获取旧的属性。

int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat);
int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat, struct mq_attr *omqstat);

入参:

  • mqdes:消息队列描述符。
  • mqstat:指向mq_attr结构的指针,用于存储或设置消息队列的属性。
  • omqstat(仅mq_setattr()):如果非NULL,则在此结构中返回旧的队列属性。

返回值:
成功时返回0,失败时返回-1并设置errno

3、编程测试

测试代码如下,编译需要加-lrt:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <fcntl.h>  
#include <sys/stat.h>  
#include <mqueue.h>  
#include <errno.h>  
#include <unistd.h>  
#include <time.h>

#define QUEUE_NAME  "/mesg_p"  
#define MAX_SIZE    1024  

// 打印时分秒的宏        
#define PRINT_MIN_SEC do { \
            time_t t = time(NULL); \
            struct tm *tm_ptr = localtime(&t); \
            printf("%02d:%02d:%02d:", tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);\
        } while (0);printf

int main(int argc, char *argv[]) 
{  
    mqd_t mqdes;  
    char buf[MAX_SIZE] = {0};  
    struct mq_attr attr;  

    // 命令行参数 
    // 第一个参数      S表示发送 R表示接收 D表示删除
    if (argc != 2) 
    {
        printf("Usage: %s S|R|D", argv[0]);
        return 0;
    }
    
    // 设置消息队列属性  
    attr.mq_flags = 0;  
    attr.mq_maxmsg = 10;  
    attr.mq_msgsize = MAX_SIZE;  
    attr.mq_curmsgs = 0;  
  
    // 打开或创建消息队列  
    mqdes = mq_open(QUEUE_NAME, O_CREAT | O_RDWR, 0644, &attr);  
    if (mqdes == (mqd_t) -1) 
    {  
        perror("mq_open");  
        exit(1);  
    }  

    if (!strcmp(argv[1], "S"))
    {
        // 发送消息  
        strcpy(buf, "Mesg 12345678!");  
        if (mq_send(mqdes, buf, strlen(buf) + 1, 0) == -1) 
        {  
            perror("mq_send");  
            exit(1);  
        } 
        PRINT_MIN_SEC("Send: %s\n", buf); 
    } 
    else if (!strcmp(argv[1], "R")) 
    {
        // 接收消息  
        memset(buf, 0, sizeof(buf));  
        if (mq_receive(mqdes, buf, MAX_SIZE, NULL) == -1) 
        {  
            perror("mq_receive");  
            exit(1);  
        }  
        
        PRINT_MIN_SEC("Received: %s\n", buf); 
    } 
    else if (!strcmp(argv[1], "D")) 
    {
        // 删除消息队列  
        if (mq_unlink(QUEUE_NAME) == -1) 
        {  
            perror("mq_unlink");  
            exit(1);  
        } 
    } 
    else
    {
        printf("Usage: %s S|R|D", argv[0]);
        return 0;
    }
 
    // 关闭消息队列  
    if (mq_close(mqdes) == -1) 
    {  
        perror("mq_close");  
        exit(1);  
    }  
  
    return 0;  
}

使用不同的传参完成指定操作,S表示发送 R表示接收 D表示删除,启用两个进程测试数据收发:

测试删除:

4、总结

本文阐述了进程间通信之消息队列(POSIX)的定义、应用场景、优缺点等,列举了编程中使用的接口,编写了测试用例测试相关功能。

  • 34
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值