进程间的通信之消息队列

转载自: https://www.ibm.com/developerworks/cn/linux/l-ipc/part3/

附录1:参考文献[unix网络编程第二卷:进程间的通信]给出了IPC随进程持续、内核持续以及随文件系统持续的定义:
1、岁进程持续:IPC一直存在到打开IPC对象的最后一个进程关闭此对象为止。如管道和命名管道

2、随内核持续:IPC一直持续到内核重新自举或者显示删除该对象为止。如消息队列、信号灯以及共享内存等;

3、随文件系统持续:IPC一直持续到显示删除该对象为止

 

消息队列(报文队列)能够克服早起unix通信机制的一些缺点

信号通信方式更想“即时”的通信方式,他要求信号的进程在某个时间范围内对信号做出反应,信号只是在进程生命周期内有意思,信号所传递的信息是接近于随进程持续的概念,见附录1;缺点:只能传输无格式的字节流,缓冲区大小受限

 

消息队列即一个消息链表。消息则看做一个记录,具有特定格式以及优先级。

对消息队列有写权限的进程可以向队列中按照一定的规则添加新的消息,对于消息队列有读权限的进程可以从消息队列中读走消息,消息队列时内核持续的。

(?消息队列中消息被读取之后是否被从消息队列中删除?)

 

系统V消息队列

1、随内核持续,只有内核重启或显式删除一个消息队列时,才被真正删除。

系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,

系统中所有消息队列都可以在msg_ids中找到访问入口

 

2、消息队列时一个消息链表,每个都有一个队列头,结构(struct msg_queue参见附录2)

包括大量信息,可以设置其中信息,此结构位于内核中

 

3、内核与消息队列建立联系:


通过struct ipc_ids msg_ids访问到每个消息队列头的第一个成员:struct kern_ipc_perm;

通过   struct kern_ipc_perm 唯一的确定一个消息队列(根据key)

 

 

对消息队列的操作

1、打开和创建消息队列

 文件名到键值

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj);

消息缓冲区结构

struct msgbuf{
long mtype;
char mtext[1];
};
 

3.系统V消息队列API
系统V消息队列API共有四个,使用时需要包括几个头文件:

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


1)int msgget(key_t key, int msgflg)

参数key是一个键值,由ftok获得;msgflg参数是一些标志位。该调用返回与健值key相对应的消息队列描述字。

在以下两种情况下,该调用将创建一个新的消息队列:

  • 如果没有消息队列与健值key相对应,并且msgflg中包含了IPC_CREAT标志位;
  • key参数为IPC_PRIVATE;


参数msgflg可以为以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果。

调用返回:成功返回消息队列描述字,否则返回-1

注:参数key设置成常数IPC_PRIVATE并不意味着其他进程不能访问该消息队列,只意味着即将创建新的消息队列。

2)int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。

msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读消息标志msgflg可以为以下几个常值的或:

  • IPC_NOWAIT 如果没有满足条件的消息,调用立即返回,此时,errno=ENOMSG
  • IPC_EXCEPT 与msgtyp>0配合使用,返回队列中第一个类型不为msgtyp的消息
  • IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将丢失。


msgrcv手册中详细给出了消息类型取不同值时(>0; <0; =0),调用将返回消息队列中的哪个消息。

msgrcv()解除阻塞的条件有三个:

  1. 消息队列中有了满足条件的消息;
  2. msqid代表的消息队列被删除;
  3. 调用msgrcv()的进程被信号中断;

调用返回:成功返回读出消息的实际字节数,否则返回-1。

 

3)int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。

对发送消息来说,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。造成msgsnd()等待的条件有两种:

  • 当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量;
  • 当前消息队列的消息数(单位"个")不小于消息队列的总容量(单位"字节数"),此时,虽然消息队列中的消息数目很多,但基本上都只有一个字节。


 

msgsnd()解除阻塞的条件有三个:

  1. 不满足上述两个条件,即消息队列中有容纳该消息的空间;
  2. msqid代表的消息队列被删除;
  3. 调用msgsnd()的进程被信号中断;


 

调用返回:成功返回0,否则返回-1。

4)int msgctl(int msqid, int cmd, struct msqid_ds *buf);
该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

  1. IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中;
  2. IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。
  3. IPC_RMID:删除msqid标识的消息队列;


 

调用返回:成功返回0,否则返回-1。

 

附录2:

结构msg_queue用来描述消息队列头,存在于系统空间

struct msg_queue {
    struct kern_ipc_perm q_perm;
    time_t q_stime;         /* last msgsnd time */
    time_t q_rtime;         /* last msgrcv time */
    time_t q_ctime;         /* last change time */
    unsigned long q_cbytes;     /* current number of bytes on queue */
    unsigned long q_qnum;       /* number of messages in queue */
    unsigned long q_qbytes;     /* max number of bytes on queue */
    pid_t q_lspid;          /* pid of last msgsnd */
    pid_t q_lrpid;          /* last receive 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;      /* first message on queue,unused  */
    struct msg *msg_last;       /* last message in queue,unused */
    __kernel_time_t msg_stime;  /* last msgsnd time */
    __kernel_time_t msg_rtime;  /* last msgrcv time */
    __kernel_time_t msg_ctime;  /* last change time */
    unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
    unsigned long  msg_lqbytes; /* ditto */
    unsigned short msg_cbytes;  /* current number of bytes on queue */
    unsigned short msg_qnum;    /* number of messages in queue */
    unsigned short msg_qbytes;  /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};
 

参考文献:

  • UNIX网络编程第二卷:进程间通信,作者:W.Richard Stevens,译者:杨继张,清华大学出版社。对POSIX以及系统V消息队列都有阐述,对Linux环境下的程序开发有极大的启发意义。
  • linux内核源代码情景分析(上),毛德操、胡希明著,浙江大学出版社,给出了系统V消息队列相关的源代码分析。
  • http://www.fanqiang.com/a4/b2/20010508/113315.html,主要阐述linux下对文件的操作,详细介绍了对文件的存取权限位,对IPC对象的存取权限同样具有很好借鉴意义。
  • msgget、msgsnd、msgrcv、msgctl手册


     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值