linux posix消息队列测试

Linux posix 消息队列思维导图

消息队列思维导图

0 测试方案

在这里插入图片描述

1.1 能否读取MAX_MSG_NUM、MAX_BYTES

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

#include <iostream>
using namespace std;

#define MQNAME "/mqtest"

int main()
{
    mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT, 0666, NULL);
    if (mqd == -1)
    {
        perror("mq_open()...");
        exit(1);
    }

    mq_attr attr;
    if (mq_getattr(mqd, &attr) < 0)
    {
        cout << "get the message queue attribute error" << endl;
        return -1;
    }

    cout << "mq_flags:" << attr.mq_flags << endl;
    cout << "mq_maxmsg:" << attr.mq_maxmsg << endl;
    cout << "mq_msgsize:" << attr.mq_msgsize << endl;
    cout << "mq_curmsgs:" << attr.mq_curmsgs << endl;

    mq_close(mqd);
    return 0;
}

输出结果:

mq_flags:0
mq_maxmsg:10
mq_msgsize:8192
mq_curmsgs:0

1.2.1 能否设置MAX_MSG_NUM、MAX_BYTES

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

#include <iostream>
using namespace std;

#define MQNAME "/mqtest"

int main(int argc, char **argv)
{
    struct mq_attr attr;
    attr.mq_msgsize = 1024;
    attr.mq_maxmsg = 20;

    mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT, 0666, &attr);
    if (mqd == -1)
    {
        perror("mq_open()...");
        exit(1);
    }

    char msg[] = "abcdefg";
    for (int i = 1; i <= 50; ++i)
    {
        if (mq_send(mqd, msg, sizeof(msg), i) < 0)
        {
            cout << "send message " << i << " failed. ";
            cout << "error info:" << strerror(errno) << endl;
        }
        else
        {
            cout << "send message " << i << " success. " << endl;
        }

        sleep(1);
    }
    mq_close(mqd);
    mq_unlink(MQNAME);
    return 0;
}

程序运行结果可以看出能发20条消息后就停了。

send message 1 success.
send message 2 success.
send message 3 success.
send message 4 success.
send message 5 success.
send message 6 success.
send message 7 success.
send message 8 success.
send message 9 success.
send message 10 success.
send message 11 success.
send message 12 success.
send message 13 success.
send message 14 success.
send message 15 success.
send message 16 success.
send message 17 success.
send message 18 success.
send message 19 success.
send message 20 success.

从消息队列文件中可以看出里面的字节数不断增长,字节数等于每次的字节数8*发送次数。

zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:112 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:120 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:128 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:136 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:144 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:152 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:160 NOTIFY:0 SIGNO:0 NOTIFY_PID:0

1.2.2 能否设置MAX_BYTES

把限制的每条消息字节数改小,实际报文改大,看在设置值前后是否分别正常和不正常

情况1 不超过设定字节数

attr.mq_maxmsg = 10;
attr.mq_msgsize = 20;
char msg[] = "1234567890123456789";//刚好20字节

send message 1 success.
send message 2 success.
send message 3 success.
send message 4 success.
send message 5 success.
send message 6 success.
send message 7 success.
send message 8 success.
send message 9 success.
send message 10 success.

zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:180 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:180 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:200 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:200 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:200 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:200 NOTIFY:0 SIGNO:0 NOTIFY_PID:0

情况2 超过设定字节数

attr.mq_maxmsg = 10;
attr.mq_msgsize = 20;
char msg[] = "12345678901234567890";//21字节,超过设置

send message 1 failed. error info:Message too long
send message 1 success.
send message 2 failed. error info:Message too long
send message 2 success.
send message 3 failed. error info:Message too long
send message 3 success.
send message 4 failed. error info:Message too long

2.1 消息数量超过了MAX_MSG_NUM,是否发送函数阻塞

上面连带测试了。

2.2 消息数量为空,是否接收函数阻塞

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

#include <iostream>
using namespace std;

#define MQNAME "/mqtest"

int main(int argc, char **argv)
{
    struct mq_attr attr;
    attr.mq_msgsize = 20;
    attr.mq_maxmsg = 10;

    mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT | O_NONBLOCK, 0666, &attr);
    if (mqd == -1)
    {
        perror("mq_open()...");
        exit(1);
    }

    char *buff = new char[attr.mq_msgsize];
    while (1)
    {
        int msg_count = mq_receive(mqd, buff, attr.mq_msgsize, NULL);
        if (msg_count >= 0)
            printf("received %ld bytes message.\n", (long) msg_count);
        else
        {
            if (errno != EAGAIN)
                printf("no message to receive\n");
            else
                printf("error = %d ,please try again!\n", errno);
        }
    }

    delete buff;

    mq_close(mqd);
    mq_unlink(MQNAME);
    return 0;
}

从下面看消息队列为空

zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:0          NOTIFY:0     SIGNO:0     NOTIFY_PID:0  

从下面看接收是阻塞的

[100%] Linking CXX executable /users/zhanf/repo/platform/bin/msg_recv
[100%] Built target msg_recv

如果发送端开始发消息

send message 1 success. 
send message 2 success. 
send message 3 success. 
send message 4 success. 
send message 5 success. 
send message 6 success. 
send message 7 success. 

接收端开始显示

[100%] Built target msg_recv
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.

2.3 消息数量超过了MAX_MSG_NUM,是否发送函数立即返回失败

打开消息队列的函数中设置O_NONBLOCK,那么发送和接收函数都是非阻塞的。

mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT | O_NONBLOCK, 0666, &attr);

从下面运行情况可以看出,在没有接收程序的情况下,发送满10条后就发送失败,是非阻塞的。

send message 1 success. 
send message 2 success. 
send message 3 success. 
send message 4 success. 
send message 5 success. 
send message 6 success. 
send message 7 success. 
send message 8 success. 
send message 9 success. 
send message 10 success. 
send message 11 failed. error info:Resource temporarily unavailable
send message 12 failed. error info:Resource temporarily unavailable
send message 13 failed. error info:Resource temporarily unavailable

2.4 消息数量为空,是否接收函数立即返回失败

用上面接收的测试程序修改一点,设置为非阻塞模式

mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT | O_NONBLOCK, 0666, &attr);

运行,发现非阻塞模式下

error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!

如果之前消息队列里面有一些消息,先正常接收,,消息队列中的字节数越来越小,收完了就会显示接收失败
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
received 20 bytes message.
error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!
error = 11 ,please try again!

zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:40 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:20 NOTIFY:0 SIGNO:0 NOTIFY_PID:0
zhanf@scada1:/dev/mqueue$ cat mqtest
QSIZE:0 NOTIFY:0 SIGNO:0 NOTIFY_PID:0

3.1 是否支持epoll方式

epoll方式的接收代码:

3.1.1 单个发送和接收程序

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

#include <iostream>
using namespace std;

#define MQNAME "/mqtest"
#define EPSIZE 10

int main()
{
    mq_attr attr;
    attr.mq_msgsize = 20;
    attr.mq_maxmsg = 10;

    //创建或打开消息队列
    mqd_t mqd = mq_open(MQNAME, O_RDWR | O_CREAT, 0666, &attr);
    if (mqd == -1)
    {
        perror("mq_open()...");
        exit(1);
    }

    //查询
    {
        mq_attr attr;
        if (mq_getattr(mqd, &attr) < 0)
        {
            cout << "get the message queue attribute error" << endl;
            return -1;
        }

        cout << "mq_flags:" << attr.mq_flags << endl;
        cout << "mq_maxmsg:" << attr.mq_maxmsg << endl;
        cout << "mq_msgsize:" << attr.mq_msgsize << endl;
        cout << "mq_curmsgs:" << attr.mq_curmsgs << endl;
    }

    //设置属性
    mq_attr new_attr, old_attr;
    new_attr.mq_flags = O_NONBLOCK;
    if (mq_setattr(mqd, &new_attr, &old_attr) == -1)
    {
        perror("mq_setattr()");
        exit(1);
    }
    printf("\nmq_maxmsg = %ld, mq_msgsize = %ld\n", old_attr.mq_maxmsg, old_attr.mq_msgsize);

    //创建epoll描述符
    int epfd = epoll_create(EPSIZE);
    if (epfd < 0)
    {
        perror("epoll_create()");
        exit(1);
    }

    /* 关注描述符是否可读 */
    epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = mqd;
    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, mqd, &ev);
    if (ret < 0)
    {
        perror("epoll_ctl()");
        exit(1);
    }

    unsigned int prio;//优先级
    char buf[BUFSIZ]; //接收缓存
    epoll_event rev;
    while (1)
    {
        ret = epoll_wait(epfd, &rev, EPSIZE, -1);
        if (ret < 0)
        {
            /* 如果被信号打断则继续epoll_wait */
            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                perror("epoll_wait()");
                exit(1);
            }
        }

        /* 此处处理所有返回的描述符(虽然本例子中只有一个) */
        for (int count = 0; count < ret; count++)
        {
            ret = mq_receive(rev.data.fd, buf, BUFSIZ, &prio);
            if (ret == -1)
            {
                if (errno == EAGAIN)
                    break;
                perror("mq_receive()");
                exit(1);
            }
            printf("recv msq: %s, prio: %d\n", buf, prio);
        }
    }

    // 恢复描述符的flag
    // if (mq_setattr(mqd, &old_attr, NULL) == -1)
    // {
    //     perror("mq_setattr()");
    //     exit(1);
    // }

    ret = mq_close(mqd);
    if (ret == -1)
    {
        perror("mp_close()");
        exit(1);
    }
    mq_unlink(MQNAME);
    return 0;
}

运行结果:

mq_flags:0
mq_maxmsg:10
mq_msgsize:20
mq_curmsgs:0

mq_maxmsg = 10, mq_msgsize = 20
recv msq: 1234567890123456789, prio: 1
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 3
recv msq: 1234567890123456789, prio: 4
recv msq: 1234567890123456789, prio: 5

3.1.2 多个发送程序和1个接收程序

因为发送程序发送的时候是带优先级的,下面函数的最后一个参数i是变的

    for (int i = 1; i <= 50; ++i)
    {
        if (mq_send(mqd, msg, sizeof(msg), i) < 0)

一个发送和一个接收程序,打印出来的是正常的优先级(prio)

recv msq: 1234567890123456789, prio: 1
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 3
recv msq: 1234567890123456789, prio: 4
recv msq: 1234567890123456789, prio: 5
recv msq: 1234567890123456789, prio: 6

如果不同时间段分别启动3个发送程序,可以看出收到的消息的优先级是3个不同的

mq_maxmsg = 10, mq_msgsize = 20
recv msq: 1234567890123456789, prio: 1
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 1
recv msq: 1234567890123456789, prio: 3
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 4
recv msq: 1234567890123456789, prio: 1
recv msq: 1234567890123456789, prio: 3
recv msq: 1234567890123456789, prio: 5
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 4
recv msq: 1234567890123456789, prio: 6
recv msq: 1234567890123456789, prio: 3

持久化

4.1 没有接收端程序,只有发送的时候,消息是否一直增加到最大数量

send message 1 success. 
send message 2 success. 
send message 3 success. 
send message 4 success. 
send message 5 success. 
send message 6 success. 
send message 7 success. 
send message 8 success. 
send message 9 success. 
send message 10 success. 
send message 11 failed. error info:Resource temporarily unavailable

zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:80         NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:100        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:100        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:120        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:140        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:140        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:160        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:160        NOTIFY:0     SIGNO:0     NOTIFY_PID:0     
zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:200        NOTIFY:0     SIGNO:0     NOTIFY_PID:0 

4.2 发送程序发送一段后停下来,然后启动接收程序,是否接收同样数量的消息后停下来

启动epoll接收程序,发现10条不同优先级的消息都能取出来,然后就停下来了

recv msq: 1234567890123456789, prio: 10
recv msq: 1234567890123456789, prio: 9
recv msq: 1234567890123456789, prio: 8
recv msq: 1234567890123456789, prio: 7
recv msq: 1234567890123456789, prio: 6
recv msq: 1234567890123456789, prio: 5
recv msq: 1234567890123456789, prio: 4
recv msq: 1234567890123456789, prio: 3
recv msq: 1234567890123456789, prio: 2
recv msq: 1234567890123456789, prio: 1

队列文件中的消息也变成0字节了

zhanf@scada1:/dev/mqueue$ cat mqtest 
QSIZE:0          NOTIFY:0     SIGNO:0     NOTIFY_PID:0   
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值