消息队列概述

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

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

消息队列也有管道一样的不足: (1)每个消息的最长字节数的上限(MSGMAX); (2)系统中消息队列的总条数也有一个上限(MSGMNI); (3)每个消息队列所能够保存的总字节数是有上限的(MSGMNB) .

查看系统限制

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

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

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

管道 vs. 消息队列

管道

消息

流管道

有边界

先进先出

可以后进先出

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 各类IPC对象所共有的数据结构*/
    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) */
};

消息队列在内核中的表示

消息在消息队列中是以链表形式保存的, 每个节点的类型类似如下:

struct msq_Node
{
    Type msq_type;  //类型
    Length msg_len; //长度
    Data msg_data;  //数据

    struct msg_Node *next;
};

消息队列API

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msgget

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

int msgget(key_t key, int msgflg);

参数:

key: 某个消息队列的名字

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

返回值:

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

msgget调用关系图

/** 示例1: 在msgflg处指定IPC_CREAT, 如果不存在该消息队列, 则创建之**/
int main(int argc, char *argv[])
{
    //指定IPC_CREAT,如果不存在, 则创建消息队列
    int msgid = msgget(1234, 0666|IPC_CREAT);
    if (msgid == -1)
        err_exit("msgget error");
    cout << "msgget success" << endl;
}
/** 示例2:IPC_CREAT|IPC_EXCL, 如果该消息队列已经存在, 则返回出错 **/
int main(int argc, char *argv[])
{
    //指定IPC_EXCL, 如果已经存在,则报告文件已经存在(错误)
    int msgid = msgget(1234, 0666|IPC_CREAT|IPC_EXCL);
    if (msgid == -1)
        err_exit("msgget error");
    cout << "msgget success" << endl;
}
/**示例3:将key指定为IPC_PRIVATE(值为0)
将key指定为IPC_PRIVATE之后,则msgget就一定会创建一个新的消息队列,
而且每次创建的消息队列的描述符都是不同的! 因此, 除非将MessageID(key)传送给其他进程(除非有关联的进程),其他进程也无法使用该消息队列(血缘fork除外)
因此, IPC_PRIVATE创建的消息队列,只能用在与当前进程有关系的进程中使用!
**/
int main(int argc, char *argv[])
{
    //指定IPC_PRIVATE
    int msgid = msgget(IPC_PRIVATE, 0666|IPC_CREAT|IPC_EXCL);
    if (msgid == -1)
        err_exit("msgget error");
    cout << "msgget success" << endl;
}
/** 示例4: 仅打开消息队列时, msgflg选项可以直接忽略(填0), 此时是以消息队列创建时的权限进行打开
**/
int main(int argc, char *argv[])
{
    int msgid = msgget(1234, 0);
    if (msgid == -1)
        err_exit("msgget error");
    cout << "msgget success" << endl;
    cout << "msgid = " << msgid << endl;
}
//示例5:低权限创建,高权限打开
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;
}



msgctl函数

功能:获取/设置消息队列的信息

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

参数:

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

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

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

/** 示例1: IPC_RMID, 删除消息队列
注意: 消息队列并没有运用”引用计数”的功能
**/
int main()
{
    int msgid = msgget(1234, 0);
    if (msgid == -1)
        err_exit("msgget error");
    if (msgctl(msgid, IPC_RMID, NULL) == -1)
        err_exit("msgctl IPC_RMID error");
    cout << "msgctl IPC_RMID success" << endl;
}
/** 示例2: IPC_STAT
**/
int main()
{
    int msgid = msgget(0x255, 0666|IPC_CREAT);
    if (msgid == -1)
        err_exit("msgget error");

    struct msqid_ds buf;
    if (msgctl(msgid,IPC_STAT,&buf) == -1)
        err_exit("msgctl error");

    printf("buf.msg_perm.mode = %o\n",buf.msg_perm.mode);   //%o以八进制打印
    printf("buf.__key = %x\n", buf.msg_perm.__key);         //%x以十六进制打印
    cout << "buf.__msg_cbytes = " << buf.__msg_cbytes << endl;
    cout << "buf.msg_qbytes = " << buf.msg_qbytes << endl;
    cout << "buf.msg_lspid = " << buf.msg_lspid << endl;
}
/** 实践:IPC_SET,一般需要先获取,然后再设置
**/
int main()
{
    int msgid = msgget(0x255, 0);
    if (msgid == -1)
        err_exit("msgget error");

    //获取消息队列的属性
    struct msqid_ds buf;
    if (msgctl(msgid,IPC_STAT,&buf) == -1)
        err_exit("msgctl error");

    //设置消息队列的属性
    buf.msg_perm.mode = 0600;
    if (msgctl(msgid, IPC_SET, &buf) == -1)
        err_exit("msgctl error");

    //获取并打印
    bzero(&buf, sizeof(buf));
    if (msgctl(msgid, IPC_STAT, &buf) == -1)
        err_exit("msgctl IPC_STAT error");
    printf("mode = %o\n", buf.msg_perm.mode);
}

附-查看系统中的IPC对象

ipcs

删除消息队列

ipcrm -q [msqid]

或  ipcrm -Q [key] #如果key不等于0的话

Linux IPC实践(4) --System V消息队列(1)的更多相关文章

  1. Linux IPC实践(6) --System V消息队列(3)

    消息队列综合案例 消息队列实现回射客户/服务器   server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid ...

  2. Linux IPC实践(5) --System V消息队列(2)

    消息发送/接收API msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由ms ...

  3. Linux进程通信之System V消息队列

    System V消息队列是Open Group定义的XSI,不属于POSIX标准.System V IPC的历史相对很早,在上个世70年代后期有贝尔实验室的分支机构开发,80年代加入System V的 ...

  4. linux c编程:System V消息队列一

    消息队列可以认为是一个消息链表,System V 消息队列使用消息队列标识符标识.具有足 够特权的任何进程都可以往一个队列放置一个消息,具有足够特权的任何进程都可以从一个给定队列读出一个消息.在某个进 ...

  5. linux网络编程之system v消息队列(二)

    今天继续学习system v消息队列,主要是学习两个函数的使用,开始进入正题: 下面则开始用代码来使用一下该发送函数: 在运行之前,先查看一下1234消息队列是否已经创建: 用上次编写的查看消息队列状 ...

  6. Linux IPC实践(13) --System V IPC综合实践

    实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...

  7. Linux IPC实践(11) --System V信号量(1)

    信号量API #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget ...

  8. Linux IPC实践(9) --System V共享内存

    共享内存API #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int ...

  9. linux网络编程之system v消息队列(一)

    经过上次对于进程通讯的一些理论的认识之后,接下来会通过实验来进一步加深对进程通讯的认识,话不多说,进入正题: 其实还可以通过管道,但是,管道是基于字节流的,所以通常会将它称为流管道,数据与数据之间是没 ...

随机推荐

  1. HashMap和ConcurrentHashMap实现原理及源码分析

    HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...

  2. 解决 Popup 位置不随窗口移动更新的问题

    Popup弹出后,因业务需求设置了StaysOpen=true后,移动窗口位置或者改变窗口大小,Popup的位置不会更新. 如何更新位置? 获取当前Popup的Target绑定UserControl所 ...

  3. 216. Combination Sum III(medium, backtrack, 本类问题做的最快的一次)

    Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...

  4. sql 复习练习

          一.基础1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- ...

  5. 代码之间-论文修改助手v1.0版本发布

    论文查重,是每个毕业生都要面临的一个令人头疼的问题,如果写论文不认真,很可能导致查重红一大片. 之前有帮助一些朋友修改论文降低重复率,做了一些工作后发现,国内的查重机构,如知网.维普等,大多数是基于关 ...

  6. HDFS基本原理及数据存取实战

    ---------------------------------------------------------------------------------------------------- ...

  7. 剑指Offer——常用SQL语句、存储过程和函数

    剑指Offer--常用SQL语句.存储过程和函数 常用SQL语句 1.在MySQL数据库建立多对多的数据表关系 2.授权.取消授权 grant.revoke grant select, insert, ...

  8. Apache shiro集群实现 (二) shiro 的INI配置

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  9. Android 网络图片加载之cude 框架

    偶然发现了这个框架,阿里图片加载用的这个框架.非常简单操作步骤. 1.首先下载软件包,直接搜Cube ImageLoader 这个. 2.加入jar文件 3.使用前的配置: public class ...

  10. Android 系统自动重启Bug(高通平台)

    点击打开链接 最近客户反馈了一个Bug,我们的系统用着用着会自动重启,尤其是在拨号的时候极容易死机或者进入下载模式.根据老大和高通的支持得到了一个解决方案. 在Android系统中,有这么一个文件夹: ...