进程间通信之Linux消息队列编程

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_37653144/article/details/83960769

消息队列

消息队列是一种以链表为结构组织的数据,存放在Linux内核中,是由各进程通过消息队列标识符来引用的一种数据传送方式。每个消息队列都有一个队列头,利用结构struct msg_queue来描述。队列头中包含了该消息队列的基本信息,包括消息队列键值、用户ID、组ID、消息数目等,甚至记录了最近对消息队列读写进程的PID。

消息队列的队列头存在于内核空间中,结构定义如下:

struct msg_queue
{
    struct ipc_perm q_perm;
    time_t q_stime;            //上一条消息的发送时间
    time_t q_rtime;            //上一条消息的接收时间
    time_t q_ctime;            //上一次修改时间
    unsigned long q_cbytes;    //当前队列中的字节数据
    unsigned long q_qnum;      //队列中的消息数量
    unsigned long q_qbytes;    //队列的最大字节数
    pid_t q_lspid;             //上一条发送消息的PID
    pid_t q_lrpid;             //上一条接收消息的PID
    struct list_head q_messages;
    struct list_head q_receivers;
    struct list_head q_senders;
};

结构msqid_ds用来设置或返回消息队列的信息,存在于用户空间中,结构定义如下:

struct msqid_ds
{
    struct ipc_perm msg_perm;
    struct msg *msg_first;     //队列中的第一条消息
    struct mag *msg_last;      //队列中的最后一条消息
    time_t q_stime;            //上一条消息的发送时间
    time_t q_rtime;            //上一条消息的接收时间
    time_t q_ctime;            //上一次修改时间
    unsigned long q_cbytes;    //当前队列中的字节数据
    unsigned long q_qnum;      //队列中的消息数量
    unsigned long q_qbytes;    //队列的最大字节数
    pid_t q_lspid;             //上一条发送消息的PID
    pid_t q_lrpid;             //上一条接收消息的PID
};

消息的结构体为ipc_perm,其结构定义如下:

struct ipc_perm
{
    //内核中用于记录消息队列的全局数据结构msg_ids能够访问到该结构
    key_t key;            //该键值唯一对应一个消息队列
    uid_t uid;            //所有者的有效用户ID
    gid_t gid;            //所有者的有效组ID
    uid_t cuid;           //创建者的有效用户ID
    gid_t cgid;           //创建者的有效组ID
    mode_t mode;          //此对象的访问权限
    unsigned long seq;    //对象的序号
};

消息队列的操作

创建或打开

Linux内核提供了msgget函数用于创建或者打开一个消息队列,其标准调用格式如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

参数msgflg说明如下:

·当参数key的取值为IPC_PRIVATE时,不管msgflg为何值,函数都将创建一个新的消息队列。

·当参数key的取值不为IPC_PRIVATE时,操作类型就取决于msgflg的值。如果msgflg中设置了IPC_CREATE位而没有设置IPC_EXCL位,则既可能执行打开操作也可能执行创建操作,这取决于内核的消息队列中是否存在相同的key值。

·当参数key的取值不是IPC_PRIVATE时,如果msgflg中同时设置了IPC_CREATE和IPC_EXCL,则只会执行创建消息队列的操作:当key的取值不与存在的任何一个消息队列ID相同时就会执行创建队列操作,否则函数就会出错返回。

因此要执行打开消息队列的操作只有一种可能:参数key不为IPC_PRIVATE,且参数msgflg不能设置IPC_EXCL。

#include <iostream>
#include <cstdlib>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        std::cerr << "参数错误\n";
        exit(1);
    }
    key_t key = ftok(*(argv+1), 1); //ftok函数生成队列键值
    if (key < 0)
    {
        std::cerr << "获取消息队列键值失败\n";
        exit(1);
    }
    int qid = msgget(key, IPC_CREATE|0666); //打开或创建队列
    if (qid < 0)
    {
        std::cerr << "创建消息队列出错\n";
        exit(1);
    }
    else
    {
        std::cout << "创建消息队列成功\n";
    }
    return 0;
}

消息队列控制

函数msgctl可以对消息队列进行以下操作:

·查看消息队列相连的数据结构

·改变消息队列的许可权限

·改变消息队列的拥有者

·改变消息队列的字节大小

·删除一个消息队列

其标准调用格式如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msgqid, int cmd, struct msqid_ds *buf);
/*
 *参数msqid为消息队列ID(msgget返回的值)
 *参数cmd为指定要求的操作
*/

其中参数cmd的取值说明如下:

参数cmd说明
操作
IPC_STAT 将msqid指定的消息队列的内核控制数据结构msqid_ds复制到buf指定的用户空间中
IPC_SET 设置msqid指定的消息队列的有效用户与组ID、操作权限以及消息队列的字节数,即设置msqid相连的数据结构msg_perm的各成员uid、gid、mode和qbytes的值为buf所指结构中给出的值
IPC_RMID 删除msqid以及它指向的消息队列、相连的数据结构

 执行IPC_STAT命令的进程必须具有消息队列的读权限,执行IPC_SET和IPC_RMID命令的进程只能是消息队列的创建者、拥有者或是特权级相符的进程。此外,只有特权进程才能增大消息队列的字节数。

消息队列的发送和接收

Linux提供了msgsnd函数用于消息队列的发送,接收则为msgrcv。标准调用格式如下:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
int msgrcv(int msqid, const void *msgp, size_t msgsz, long msgtyp, int msgflg);

猜你喜欢

转载自blog.csdn.net/qq_37653144/article/details/83960769