Linux_POSIX消息队列

初探POSIX消息队列:在Linux下使用c语言

前言

POSIX 消息队列(POSIX Message Queues)是 POSIX IPC(进程间通信)机制的一种,它允许进程间通过发送和接收具有固定最大长度的消息来进行通信。与管道和命名管道相比,POSIX 消息队列提供了更高级的功能,例如消息类型化和非阻塞操作。本文将指导你如何在 Linux 环境下使用 C 语言编写程序来操作 POSIX 消息队列。

常用函数介绍

在POSIX消息队列中,我们常用的主要的函数有:

#include <mqueue.h> 
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr attr ); 

int mq_close(mqd_t mqdes);// int mq_unlink(const char *name); 

int mq_getattr(mqd_t mqdes, struct mq_attr *attr); 

int mq_setattr(mqd_t mqdes, struct mq_attr *attr, struct mq_attr *oattr); 

int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio); 

ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *prio); 

int mq_notify(mqd_t mqdes, const struct sigevent *notification);

mqd_t mq_open函数

这个函数用来创建或者打开一个消息队列。该函数需要指定队列的名称、打开标志和模式。

原型:

mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr attr );

参数说明:
  • name:需要打开的消息队列名称,队列名称以 / 开头,表示它在文件系统的某个位置(通常是 /dev/mqueue/),但通常我们不需要直接访问它。
  • oflag:oflag有O_RDONLY、O_RDWR, O_WRONLY,除此之外还有 O_CREAT、O_EXCL(如果 O_CREAT 指定,但name 不存在,就返回错误),O_NONBLOCK(以非阻塞方式打开消息队列,在正常情况下mq_receive和mq_send 函数会阻塞的地方,使用该标志打开的消息队列会返回 EAGAIN 错误)。
  • mode:用于指定权限位, 比如0644权限 。
  • attr:是一个结构体,用于指定消息队列的属性。
关于 struct mq_attr属性结构
struct mq_attr
{
    long mq_flags;//阻塞标志, 0(阻塞)或O_NONBLOCK
    long mq_maxmsg;//最大消息数
    long mq_msgsize;//每个消息最大大小
    long mq_curmsgs;//当前消息数
};

mq_send函数

使用该函数向队列发送消息。该函数需要指定队列描述符、指向消息的指针、消息大小和优先级

原型:

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

参数说明:
  • mqdes:消息队列的描述符,由mq_open函数返回。
  • msg_ptr:指向要发送的消息的指针
  • msg_len:要发送的消息的字节数。
  • msg_prio:消息的优先级。

注意:

POSIX消息队列允许发送带有优先级的消息,其中优先级较高的消息相对优先级较低的消息更早被接收。当参数值为0时,这意味着发送的消息具有默认(或最低,具体取决于实现)的优先级。如果应用程序不关心消息的具体优先级或者所有消息都应同等对待,通常会使用这样的默认值。

mq_receive函数

使用该函数向队列发送消息。该函数需要指定队列描述符、指向消息的指针、消息大小和优先级

原型:

ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);

参数说明:
  • mqdes:消息队列的描述符,由mq_open函数返回。
  • msg_ptr:指向一个缓冲区,用于存储接收到的消息内容。这个缓冲区应该足够大以容纳整个消息。如果消息比缓冲区大,超出部分将被截断。
  • msg_len:类型为size_t,指定了msg_ptr指向的缓冲区的大小。这有助于防止缓冲区溢出。
  • msg_prio:类型为unsigned int指针(unsigned int *),可选参数。如果非NULL,接收函数会在成功接收消息后,通过这个指针返回消息的优先级。如果不关心优先级,可以传入NULL。

注意:

  • 使用前需要通过mq_open函数打开消息队列,并且可以通过mq_getattr获取队列属性,以便正确设置缓冲区大小。
  • 若要实现非阻塞接收,可以使用fcntl函数设置消息队列描述符的O_NONBLOCK标志。
  • 传递给msg_prio的指针应当指向一个有效的unsigned int变量,以接收消息的优先级信息,除非你对优先级不感兴趣。

实现POSIX消息队列的基本操作

1. 创建消息队列

首先,我们需要使用mq_open函数来创建或打开一个消息队列。示例代码如下:

#include <stdio.h>
#include <mqueue.h>
#include <pthread.h>

#define MYQUEUE "/test_queue"

int main(int argc,char *argv[]) {

    pthread_t sender,receiver;
    struct mq_attr attr;
    attr.mq_flags = 0; // 阻塞模式
    attr.mq_maxmsg = 10;    // 最大消息数量
    attr.mq_msgsize = 256;  // 每个消息最大大小
    attr.mq_curmsgs = 0;    // 当前0个消息
    mqd_t mqdes = mq_open(MYQUEUE,O_CREAT|O_RDWR,0666,&attr); // 创建一个消息队列
    if(mqdes == -1)
    {
        perror("mq_open");
        return -1;
    }  

    if(-1 == pthread_create(&sender,NULL,sender_thread,NULL))
    {
        perror("sender pthread_create");
        return -1;
    }
    if( -1 == pthread_create(&receiver,NULL,receiver_thread,NULL))
    {
        perrort("receiver pthread_create");
        return -1;
    }

    pthread_join(sender,NULL);
    pthread_join(receiver,NULL);
    return 0;
}

代码中,创建了两个线程,一个线程做发消息的操作,另一个线程做接收的操作。我们在main函数中使用mq_open函数首先创建了一个POSIX消息队列在tem/myqueue,

2. 发送消息

我们在发送消息线程中,使用mq_send函数发送消息到消息队列。

void *sender_thread(void *arg)
{
    mqd_t mqdes = *(mqd_t *)arg;
    char message[] = MESAGE;
    printf("send thread begin\n");
    int ret = mq_send(mqdes,message,strlen(message) + 1,0); // 发送消息,优先级为0
    if(-1 == ret)
    {
        if(errno == EAGAIN)
        {
            printf("The queue was full\n");    // 消息队列已满,继续发送
        }
        else{
            perror("mq_send");
            return NULL;
        }
        
    }  
    printf("send thread end\n");
    return NULL;
}

注意:发送的消息是字节流,不包括任何终止字符(如 null 字符)。因此,在上面的示例中,我们添加了 +1 来发送字符串及其终止字符。

3. 接收消息

在接收线程中,我们使用mq_receive函数对消息队列进行接收消息,并缓存到buf中。

void *receiver_thread(void *arg)
{
    char buf[256];
    mqd_t mqdes = *(mqd_t *)arg;
    printf("receive thread begin\n");
    int ret = mq_receive(mqdes,buf,256,NULL); // 接收消息
    printf("receive message is :%s\n",buf);
    if(-1 == ret)
    {
        perror("mq_receive");
        return NULL;
    }
    printf("receive thread end\n");
}

4. 关闭消息队列

5. 删除消息队列

关闭和删除则最好处理,采用以下函数。

mq_close(mqdes);
mq_unlink(MYQUEUE);
### LinuxPOSIX 消息队列的使用 #### 创建和打开消息队列 为了创建或访问现有的 POSIX 消息队列,可以调用 `mq_open` 函数。此函数接受两个参数:一个是表示消息队列名称的字符串;另一个是指定操作模式(如只读、只写或创建新队列)的标志位集合。 如果尝试通过 `mq_open` 打开一个不存在的消息队列为只读或只写,则会失败并返回错误码 "Function not implemented" 或其他类似的错误信息[^2]。这可能是由于系统配置问题或是内核模块未加载所致。确保系统的适当设置以及必要的支持库已被安装。 ```c #include <mqueue.h> // ... const char* name = "/my_queue"; int oflag = O_CREAT | O_RDWR; mode_t mode = S_IRUSR | S_IWUSR; // 用户具有读写权限 struct mq_attr attr; attr.mq_flags = 0; attr.mq_maxmsg = 10; attr.mq_msgsize = sizeof(int); attr.mq_curmsgs = 0; mqd_t mqdes = mq_open(name, oflag, mode, &attr); if (mqdes == (mqd_t)-1) { perror("Failed to open message queue"); } ``` #### 发送消息至消息队列 一旦成功打开了消息队列,就可以利用 `mq_send` 来向其发送数据包。下面展示了一个简单的例子,在这里定义了一个名为 `sender_thread` 的线程函数负责将一条消息放入指定的消息队列中: ```c void *sender_thread(void *arg) { mqd_t mqdes = *(mqd_t *) arg; const char message[] = "Hello from sender!"; int ret = mq_send(mqdes, message, strlen(message) + 1, 0); // 发送消息,优先级设为0 if (-1 == ret && errno != EAGAIN) { // 如果不是因为队列满了导致的EAGAIN错误 perror("Error occurred while sending a message:"); return NULL; } printf("Message sent successfully.\n"); return NULL; } ``` 这段代码展示了如何在一个独立的工作单元里执行发送任务,并处理可能发生的异常情况,比如当目标队列已经达到最大容量时产生的 `EAGAIN` 错误[^3]。 #### 接收来自消息队列的消息 接收端可以通过 `mq_receive` 函数获取存储于队列内的最新可用消息。需要注意的是,接收到的数据长度由传给它的缓冲区大小决定,因此应当合理规划这些参数以适应实际应用场景的需求。 ```c char buffer[MESSAGE_SIZE]; unsigned int priority; ssize_t bytes_received = mq_receive(mqdes, buffer, MESSAGE_SIZE, &priority); if (bytes_received >= 0) { printf("Received message with length %zd and content '%s'\n", bytes_received, buffer); } else { perror("Receiving failed:"); } ``` 以上就是关于在 Linux 下使用 POSIX 消息队列的一些基本介绍及其具体实现细节[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坏柠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值