Linux进程通信:消息队列

对消息队列的理解
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,传输的数据块类型可以由消息接收者自行解析,消息队列不仅可以用在不同进程间通信,也可以在不同线程间通信,具体看实际应用
linux系统提供了几个系统调用方便应用层调用,以下为消息队列用到的几个系统调用

msgget()函数

原型 意义
int msgget(key_t, key, int msgflg); 创建和访问一个消息队列
参数 意义
key 键来命名某个特定的消息队列
msgflg 权限标志,表示消息队列的访问权限, 和IPC_CREAT做或操作,当队列不存在时创建,否则打开

msgsnd()函数

原型 意义
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); 把消息添加到消息队列中
参数 意义
msgid 由msgget函数返回的消息队列标识符
msg_ptr 指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体,接收函数将用这个成员来确定消息的类型
msg_sz msg_ptr指向的消息的长度, 注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度
msgflg 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情,0为阻塞

msgrcv()函数

原型 意义
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg); 从消息队列获取消息

如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息

参数 意义
msgid 由msgget函数返回的消息队列标识符
msg_ptr 和msgsnd一样,但指向准备接收消息的指针
msg_st 和msgsnd一样,msg_ptr指向的消息的长度, 注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度
msgtype 可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息
msgflg 用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情,0为阻塞

msgctl()函数

原型 意义
int msgctl(int msgid, int command, struct msgid_ds *buf); 该函数用来控制消息队列
参数 意义
msgid 由msgget函数返回的消息队列标识符
command command是将要采取的动作,它可以取3个值, IPC_STAT,IPC_SET,IPC_RMID
buf 指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构
command 意义
IPC_STAT 把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值
IPC_SET 如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID 删除消息队列

消息队列实现:
github源码

#include "msgqueue.h"

/**
 * @brief 创建一个消息队列
 * @param name 消息队列名称
 * @return 返回一个消息队列标识符MESSAGEQ_ID
 */
MESSAGEQ_ID create_msgqueue(char * name)
{
    char syscmd[32] = {0x00};
    char filename[32] = {0x00};

    snprintf(filename, sizeof(filename), "/tmp/%s.msgq", name);

    snprintf(syscmd, sizeof(syscmd), "rm -f %s", filename);
    system(syscmd);

    snprintf(syscmd, sizeof(syscmd), "touch %s", filename);
    system(syscmd);

    key_t key = ftok(filename, 0x01);

    MESSAGEQ_ID id = msgget(key,IPC_CREAT | 0755);

    return id;
}

/**
 * @brief 推送一条消息到消息队列
 * @param msgqid, 消息队列标识
 * @param msg, 推送的消息指针
 * @param msglen, 推送消息长度
 * @return bool, success or not
 */
bool msgqueue_post(MESSAGEQ_ID msgqid, uint8_t * msg, uint8_t msglen)
{
     MsgQueue_t Msgs =
    {
        .msgtype = 1,
        .msgbuff = {0},
    };

    if(msg == NULL || msglen == 0 || msglen > sizeof(Msgs.msgbuff))
        return false;

    memcpy(Msgs.msgbuff, msg, msglen);
    msgsnd(msgqid, &Msgs, sizeof(Msgs.msgbuff), 0);

    return true;
}

/**
 * @brief 获取消息
 * @param msgqid, 消息队列标识
 * @param msg, 获取的消息存储缓冲区指针
 * @param msglen, 能够存的最大消息长度
 * @return bool, success or not
 */
bool msgqueue_wait(MESSAGEQ_ID msgqid, uint8_t * msg, uint8_t msglen)
{
    MsgQueue_t Msgs;

    if(msg == NULL || msglen == 0 || msglen > sizeof(Msgs.msgbuff))
        return false;

    msgrcv(msgqid, &Msgs, sizeof(Msgs.msgbuff), 0, 0);

    memcpy(msg, Msgs.msgbuff, msglen);

    return true;
}

/**
 * @brief 获取消息队列中的缓冲的消息数量
 * @param msgqid, 消息队列标识
 * @return uint32_t, the result
 */
uint32_t msgqueue_getSize(MESSAGEQ_ID msgqid)
{
    struct msqid_ds buffer;

    msgctl(msgqid, IPC_STAT, &buffer);

    return buffer.msg_qnum;
}

/**
 * @brief 删除消息队列
 * @param msgqid消息队列标识
 */
void msgqueue_delete(MESSAGEQ_ID msgqid)
{
    msgctl(msgqid, IPC_RMID, NULL);
}
发布了45 篇原创文章 · 获赞 38 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/muchong123/article/details/105165782
今日推荐