初探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);
967

被折叠的 条评论
为什么被折叠?



