【APUE】进程间通信之消息队列

三种IPC的共同特征

1.标识符和键

每个内核中的IPC结构都用一个非负整数的标识符加以引用。当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整型数的最大值,然后又回转到0

标识符是IPC对象的内部名,为使多个合作进程能够在同一IPC对象上会合,需要提供一个外部名,即键

无论何时创建IPC结构,都应指定一个键,键的数据类型是基本系统数据类型key_t.键由内核变换成标识符

2.权限结构

XSI IPC为每一个IPC结构设置了一个ipc_perm结构。该结构规定了权限和所有者。

struct ipc_perm

{

  uid_t uid;

  gid_t gid;

  ...

};

3.优点和缺点

1)IPC结构没有访问计数,当没有进程访问时,也不会自动删除

2)IPC结构在文件系统中没有名字

3)IPC不使用文件描述符,不能对它们使用多路转接I/O函数:select和poll

IPC随进程持续、随内核持续以及随文件系统持续的定义:
1. 随进程持续:IPC一直存在到打开IPC对象的最后一个进程关闭该对象为止。如管道和有名管道;
2. 随内核持续:IPC一直持续到内核重新自举(即重启)或者显式删除该对象为止。如消息队列、信号灯以及共享内存等;
3. 随文件系统持续:IPC一直持续到显示删除该对象为止。

消息队列

(1)消息缓冲区(msgbuf)

我们在这里要介绍的第一个数据结构是msgbuf结构,可以把这个特殊的数据结构看成一个存放消息数据的模板,它在include/linux/msg.h中声明,描述如下:

/* msgsnd 和msgrcv 系统调用使用的消息缓冲区*/

struct msgbuf {

    long mtype;         /* 消息的类型,必须为正数 */

    char mtext[1];      /* 消息正文 */

};

注意:对于消息数据元素(mtext),不要受其描述的限制。实际上,这个域(mtext)不仅能保存字符数组,而且能保存任何形式的任何数据。这个域本身是任意的,因为这个结构本身可以由应用程序员重新定义:

struct my_msgbuf {

      long    mtype;          /* 消息类型 */

        long    request_id;     /* 请求识别号 */

        struct client info;    /* 客户消息结构 */

};

我们看到,消息的类型还是和前面一样,但是结构的剩余部分由两个其它的元素代替,而且有一个是结构。这就是消息队列的优美之处,内核根本不管传送的是什么样的数据,任何信息都可以传送。

但是,消息的长度还是有限制的,在Linux中,给定消息的最大长度在include/linux/msg.h中定义如下:

#define MSGMAX 8192    /* max size of message (bytes) */

消息总的长度不能超过8192字节,包括mtype域,它是4字节长。

(2)消息结构(msg)

内核把每一条消息存储在以msg结构为框架的队列中,它在include/ linux/msg.h中定义如下:

struct msg {

    struct msg *msg_next;   /* 队列上的下一条消息 */

    long msg_type;          /*消息类型*/

    char *msg_spot;         /* 消息正文的地址 */

    short msg_ts;           /* 消息正文的大小 */

};

注意:msg_next是指向下一条消息的指针,它们在内核地址空间形成一个单链表。

(3)消息队列结构(msgid_ds)

当在系统中创建每一个消息队列时,内核创建、存储及维护这个结构的一个实例。

/* 在系统中的每一个消息队列对应一个msqid_ds 结构 */

struct msqid_ds {

    struct ipc_perm msg_perm;

    struct msg *msg_first;    /* 队列上第一条消息,即链表头*/

    struct msg *msg_last;    /* 队列中的最后一条消息,即链表尾 */

    time_t msg_stime;        /* 发送给队列的最后一条消息的时间 */

    time_t msg_rtime;            /* 从消息队列接收到的最后一条消息的时间 */

    time_t msg_ctime;             /* 最后修改队列的时间*/

    ushort msg_cbytes;          /*队列上所有消息总的字节数 */

    ushort msg_qnum;          /*在当前队列上消息的个数 */

    ushort msg_qbytes;        /* 队列最大的字节数 */

    ushort msg_lspid;           /* 发送最后一条消息的进程的pid */

    ushort msg_lrpid;           /* 接收最后一条消息的进程的pid */

};

消息队列具有队列的基本特征,也具有其独特的性质。在消息队列中,入列称为发送消息,出列称为接收消息。除此之外,消息队列还具有以下特征。

1)消息队列中的消息是有类型的同一类型的消息放在同一个消息链表中,多个消息链表形成一个消息队列。在发送一条消息时,可以指定消息类型;在接收进程中,可以按照该消息类型从消息队列中获取数据。在实际应用中,可以多个应用共用一个队列,用消息类型区分不同的应用。
2)消息队列中的消息按照发送的顺序排队,对于相同类型的消息,先进入消息队列的消息先被接收。
消息队列提供了一种在两个不相关的进程之间传递数据的简单高效的方法。与有名管道比较起来,消息队列的优点在独立于发送与接收进程,这减少了在打开与关闭有名管道之间同步的困难

参考:

http://blog.chinaunix.net/uid-197233-id-3083911.html

posted @ 2014-07-19 15:56  合唱团abc  阅读(294)  评论(0编辑  收藏  举报