首页 > 代码库 > Linux消息队列基础

Linux消息队列基础

消息队列基本概念

    消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限与本机)

    每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

    消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)

 

管道 vs. 消息队列:

管道: 流管道          消息: 有边界

   先进先出            可以后进入、先出来

 

消息队列大小三大限制

   cat /proc/sys/kernel/msgmax  #最大消息长度限制

   cat /proc/sys/kernel/msgmnb  #消息队列总的字节数

   cat /proc/sys/kernel/msgmni  #消息条目数

 

 

IPC对象数据结构

   内核为每个IPC对象维护一个数据结构

struct ipc_perm
{
    key_t          __key;       /* Key supplied to msgget(2) */
    uid_t          uid;         /* Effective UID of owner */
    gid_t          gid;         /* Effective GID of owner */
    uid_t          cuid;        /* Effective UID of creator */
    gid_t          cgid;        /* Effective GID of creator */
    unsigned short mode;        /* Permissions */
    unsigned short __seq;       /* Sequence number */
};

 

消息队列特有的结构

struct msqid_ds
{
    struct ipc_perm msg_perm;     /* Ownership and permissions */
    time_t          msg_stime;    /* Time of last msgsnd(2) */
    time_t          msg_rtime;    /* Time of last msgrcv(2) */
    time_t          msg_ctime;    /* Time of last change */
    unsigned long   __msg_cbytes; /* Current number of bytes in
                                                queue (nonstandard) */
    msgqnum_t       msg_qnum;     /* Current number of messages
                                                in queue */
    msglen_t        msg_qbytes;   /* Maximum number of bytes
                                                allowed in queue */
    pid_t           msg_lspid;    /* PID of last msgsnd(2) */
    pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
};

 

消息队列在内核中的表示


消息队列函数示例

msgget函数 

功能:用来创建访问一个消息队列

原型:

int msgget(key_t key, int msgflg);

参数:

    key: 某个消息队列的名字

    msgflg:由九个权限标志构成,如0644,它们的用法和创建文件时使用的mode模式标志是一样的(但是消息队列没有x(执行)权限)

 

返回值:

   成功返回消息队列编号,即该消息队列的标识码;失败返回-1

 

编程实践

//实践1:	IPC_PRIVATE:宏,值为0
int main()
{
  //IPC_PRIVATE每次创建的消息队列的描述符都是不同的!
  //因此,计时MessageID(key)传送给其他进程(除非有关联的进程),
  //其他进程也无法使用该消息队列(血缘fork除外)
    int msgid = msgget(IPC_PRIVATE,0666);
    if (msgid < 0)
    {
        //如果消息队列不存在,则打开错误,errno=ENOENT
        if (errno == ENOENT)
        {
            cout << "ENOENT" << endl;
        }
        err_exit("mesget error");
    }
    else
    {
        cout << "msgid = " << msgid << endl;
    }

    return 0;
}
/**
  IPC_PRIVATE创建的消息队列,只能用在与当前进程有关系的进程中使用!
*/


//实践2:	IPC_CREAT
int main()
{
    //指定IPC_CREAT,则一定会创建消息队列
    int msgid = msgget(0x1235,0666|IPC_CREAT);
    if (msgid < 0)
    {
        //如果消息队列不存在,则打开错误,errno=ENOENT
        if (errno == ENOENT)
        {
            cout << "ENOENT" << endl;
        }
        err_exit("mesget error");
    }
    else
    {
        cout << "msgid = " << msgid << endl;
    }

    return 0;
}


//实践3:	IPC_CREAT|IPC_EXCL
int main()
{
    //指定IPC_EXCL, 如果已经存在,则报告文件已经存在(错误)
    int msgid = msgget(0x1235,0666|IPC_CREAT|IPC_EXCL);
    if (msgid < 0)
    {
        err_exit("mesget error");
    }
    else
    {
        cout << "msgid = " << msgid << endl;
    }

    return 0;
}




//实践4:低权限创建,高权限打开
int main()
{
    //低权限创建
    int msgid = msgget(0x255,0444 | IPC_CREAT);
    if (msgid < 0)
    {
        err_exit("mesget error");
    }
    else
    {
        cout << "Create Mes OK, msgid = " << msgid << endl;
    }

    //高权限打开
    msgid = msgget(0x255,0644 | IPC_CREAT);
    if (msgid < 0)
    {
        err_exit("mesget error");
    }
    else
    {
        cout << "Create Mes OK, msgid = " << msgid << endl;
    }

    return 0;
}


msgget函数参数关系图

 

 

msgctl函数

功能:对消息队列进行控制

原型:

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

参数:

    msqid: 由msgget函数返回的消息队列标识码

    cmd:是将要采取的动作(见下)

 

返回值:

   成功返回0,失败返回-1

 

cmd:将要采取的动作(有三个可取值),分别如下:


Linux消息队列基础