一、    概念

消息队列就是一个消息的链表。对消息队列有写权限的进程可以向其中按照一定的规则添加新消息;对消息队列有读权限的进程可以从消息队列中读出消息。消息队列是随内核持续的。下面介绍三个概念:

1;随进程持续:IPC一直存在,直至打开IPC对象的最后一个进程关闭该对象为止,如管道和有名管道

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

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

System V消息队列目前被大量使用。

二、    消息队列的信息

每个消息队列都有一个队列头,用结构struct msg_queue来描述。队列头中包含了该消息队列的大量信息,包括消息队列键值、用户ID、组ID、消息队列中消息数目等等,甚至记录了最近对消息队列读写进程的ID。读者可以访问这些信息,也可以设置其中的某些信息。这个结构存于系统空间。

struct msg_queue {
structkern_ipc_perm q_perm;
time_tq_stime; /* last msgsndtime */
time_tq_rtime; /* last msgrcvtime */
time_tq_ctime; /* last changetime */
unsignedlong q_cbytes; /* current number of bytes on queue*/
unsignedlong q_qnum; /* number of messages inqueue */
unsignedlong q_qbytes; /* max number of bytes on queue */
pid_tq_lspid; /* pid oflast msgsnd */
pid_tq_lrpid; /* lastreceive pid */
structlist_head q_messages;
structlist_head q_receivers;
structlist_head q_senders;
};

结构msqid_ds用来设置或返回消息队列的信息,存在于用户空间;

structmsqid_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 32bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of byteson queue */
unsigned short msg_qnum; /* number of messages in queue*/
unsigned short msg_qbytes; /* max number of bytes onqueue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid*/
};

三、    打开创建消息队列

消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,只需提供该消息队列的键值即可。msgget用于创建一个消息队列或打开一个现存的队列。

名称::

msgget

功能:

创建消息队列

头文件:

#include <sys/types.h>

#include <sys/msg.h>

#inlcude <sys/ipc.h>

函数原形:

int msgget(key_t key,int msgflag);

参数:

key 消息队列的键

flag 一些标志位

返回值:

若成功则为消息队列描述字若出错则为-1。

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

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

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

2.key参数为IPC_PRIVATE;

参数msgflg可以为以下:IPC_CREAT(创建消息队列)、IPC_EXCL(  )、IPC_NOWAIT(  )或三者的或结果。

还有注意的是:当创建一个新队列时,系统自动初始化struct msqid_ds结构的下列成员。

ipc_perm结构按我们以前说的进行初始化。该结构中mode成员按flag中的相应权限位设置。

msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime都设置为0。

msg_ctime设置为当前时间。

msg_qbytes设置为系统限制值。

四、获得和修改消息队列属性,删除消息队列

名称::

msgctl

功能:

对消息队列进行多种操作

头文件:

#include <sys/msg.h>

函数原形:

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

参数:

msqid   消息队列描述字

cmd    要执行的操作

buf     此队列的struct msqid_ds结构

返回值:

若成功返回0,若出错返回-1。

该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET、IPC_RMID。

IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid_da结构中;

IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid_ds结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。

IPC_RMID:删除msqid_ds标识的消息队列.

五、用消息队列发送和接收消息

名称::

msgsnd

功能:

将数据放到消息队列上

头文件:

#include <sys/types.h>

#include <sys/msg.h>

#inlcude <sys/ipc.h>

函数原形:

int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);

参数:

msqid   消息队列描述字

msgp       指向消息数据的指针

msgsz    发送消息的大小

msgflg       标志位

返回值:

若成功则为0,若出错则为-1。

向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。

structmsgbuf{

longmtype; /*消息类型*/

charmtext[1]; /*消息数据*/

};

我们可以把msgbuf结构看成是一个模版,程序员可以根据自己的需要来设计直接的消息结构。举例来说,如果某个应用需要交换由一个整数后跟一个8字节字符数组构成的消息,那它可以如下定义自己的结构:

typedefstruct my_msgbuf{

longmtypel

int    mshort;

char mchar[MY_DATA];

}Message;

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

1.当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量;

2.当前消息队列的消息数(单位"个")不小于消息队列的总容量(单位"字节数"),此时,虽然消息队列中的消息数目很多,但基本上都只有一个字节。

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

1.不满足上述两个条件,即消息队列中有容纳该消息的空间;

2.msqid代表的消息队列被删除;

3.调用msgsnd()的进程被信号中断;

当msgsnd成功返回,与消息队列相关的msqid_ds结构得到更新,以标明发出该调用的进程ID(msg_lspid),进行该调用的时间(msg_stime),并指示队列中增加了一条消息。

 六、消息队列的使用

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
void msg_stat(int,struct msqid_ds ); int main(void)
{
int gflags,sflags,rflags;
key_t key;
int msgid;
int reval;
struct msgsbuf
{
int mtype;
char mtext[1];
}msg_sbuf; /*发送消息缓冲区数据结构*/
struct msgmbuf
{
int mtype;
char mtext[10];
}msg_rbuf; /*接收消息缓冲区数据结构*/
struct msqid_ds msg_ginfo,msg_sinfo;
char* msgpath="/unix/msgqueue";
key=ftok(msgpath,'a'); /*获取消息队列键值*/
gflags=IPC_CREAT|IPC_EXCL;
msgid=msgget(key,gflags|00666); /*调用msgget创建消息队列*/
if(msgid==-1)
{
printf("msg create error\n");
return;
}
msg_stat(msgid,msg_ginfo);
/*创建一个消息队列后,输出消息队列缺省属性。第一次调用msg_stat 子函数*/
sflags=IPC_NOWAIT; /*消息队列满时,msgsnd 不等待,立刻出错返回*/
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a'; /*将要发送的消息数据*/
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags); /*调用msgsnd发送消息*/
if(reval==-1)
{
printf("message send error\n");
}
msg_stat(msgid,msg_ginfo);
/*成功发送一个消息后,输出此时消息队列属性。第二次调用msg_stat 子函数*/
rflags=IPC_NOWAIT|MSG_NOERROR; /*含义见表10.1*/
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
/*调用msgrcv接收消息,接收数据长度为4,type > 0,含义见表10.2*/
if(reval==-1)
{
printf("read msg error\n");
}
else
{
printf("read from msg queue %d bytes\n",reval); /*打印接收到数据的字节数*/
}
msg_stat(msgid,msg_ginfo);
/*从消息队列中读出消息后,再次输出消息队列属性。第三次调用msg_stat 子函数*/
msg_sinfo.msg_perm.uid=8;
/*试图更改消息队列的缺省属性(要求root用户权限),所有者有效用户ID更改为8*/
msg_sinfo.msg_perm.gid=8;
/*消息队列的所有者有效组ID更改为8*/
msg_sinfo.msg_qbytes=16388;
/*消息队列可容纳最大字节数更改为16388(缺省为16384)*/
reval=msgctl(msgid,IPC_SET,&msg_sinfo); /*调用msgctl设置消息队列属性*/
if(reval==-1)
{
printf("msg set info error\n");
return;
}
msg_stat(msgid,msg_ginfo); /*验证设置消息队列属性。第三次调用msg_stat 子函数*/
reval=msgctl(msgid,IPC_RMID,NULL); /* 操作完毕,调用msgctl删除消息队列*/
if(reval==-1)
{
printf("unlink msg queue error\n");
return;
}
return 0;
} void msg_stat (int msgid,struct msqid_ds msg_info)
{
int reval;
sleep(1); /*只是为了后面输出时间的方便*/
reval=msgctl(msgid,IPC_STAT,&msg_info); /*调用msgctl 获得消息队列属性信息*/
if(reval==-1)
{
printf("get msg info error\n");
return;
}
printf("\n");
printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);
printf("number of messages in queue is %d\n",msg_info.msg_qnum);
printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);
/*每个消息队列的容量(字节数)都有限制MSGMNB,值的大小因系统而异。在创建*/
/*新的消息队列时,msg_qbytes的缺省值就是MSGMNB*/
printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
/*最近一个执行msgsnd函数的进程ID*/
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
/*最近一个执行msgrcv函数的进程ID*/
printf("last msgsnd time is %s", ctime(&(msg_info.msg_stime)));
/*最近一次执行msgsnd函数的时间。ctime()将时间转变成周、月、日、时分秒、年的*/
/*形式,属于标准C函数*/
printf("last msgrcv time is %s", ctime(&(msg_info.msg_rtime)));
/*最近一次执行msgrcv函数的时间*/
printf("last change time is %s", ctime(&(msg_info.msg_ctime)));
/*最近一次改变该消息队列的时间*/
printf("msg uid is %d\n",msg_info.msg_perm.uid);/*消息队列所有者的有效用户ID*/
printf("msg gid is %d\n",msg_info.msg_perm.gid); /*消息队列所有者的有效组ID*/
}

IPC之消息队列详解与使用的更多相关文章

  1. kafka以及消息队列详解

    Kafka 是LinkedIn 开发的一个高性能.分布式的消息系统. 用途:广泛用于日志收集.流式数据处理.在线和离线消息分发等场景. 1. Kafka 将消息流按Topic 组织,保存消息的服务器称 ...

  2. 【转】windows消息和消息队列详解

    转载出处:http://blog.csdn.net/bichenggui/article/details/4677494  windows消息和消息队列 与基于MS - DOS的应用程序不同,Wind ...

  3. PHP 消息队列 详解

    前言:之前做过的一些项目中有时候会接触到消息队列,但是对消息队列并没有一个很清楚的认知,本篇文章将会详细分析和归纳一些笔记,以供后续学习. 一.消息对列概念 从本质上说消息对列就是一个队列结构的中间件 ...

  4. Windows 消息以及消息处理算法--线程和消息队列详解

    Windows以消息驱动的方式,使得线程能够通过处理消息来响应外界. Windows 为每个需要接受消息和处理消息的线程建立消息队列(包括发送消息队列,登记消息队列,输入消息队列,响应消息队列),其中 ...

  5. 数据结构图文解析之:队列详解与C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  6. System V IPC(1)-消息队列

    一.概述                                                    System V三种IPC:消息队列,信号量,共享内存.这三种IPC最先出现在AT&am ...

  7. Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)

    有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...

  8. Android开发——Android的消息机制详解

    )子线程默认是没有Looper的,Handler创建前,必须手动创建,否则会报错.通过Looper.prepare()即可为当前线程创建一个Looper,并通过Looper.loop()来开启消息循环 ...

  9. Linux进程间通信:IPC对象——信号灯集详解

    作者:倪老师,华清远见嵌入式学院讲师. 一.信号灯概述 信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制.相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时 ...

随机推荐

  1. 关于Android开发中导出jar包后的资源使用问题解决

    我们经常遇到一个需求,就是给别人使用我们工程的时候,为了能够屏蔽代码,把代码封装成jar包提供给第三方使用,但是这样我们的资源文件怎么给对方用呢? 其实并不用这么的复杂,下面就介绍一下具体的方法 一, ...

  2. MPEG-DASH on IIS Practice in Action

    1. 准备  IIS Media Service已经安装准备好(如上),注意需要在2008上安装,2003安装不了,或者就算能安装也很麻烦 一个或多个码率的媒体文件如MP4已经准备好 DASH MPD ...

  3. hdu1005 Number Sequence

    f(n-1)和f(n-2)所有组合都49种子,这期可达49,但f(n-1)=f(n-2)=0如果是,列的总数目0.话题条件f(1)=f(2)=1.因此排除这样的情况.的最长期限48. #include ...

  4. 使用TeamCity对项目进行可持续集成管理

    使用TeamCity对项目进行可持续集成管理 一.可持续集成管理   持续集成,CI:即Continuous integration. 可持续集成的概念是基于团队(小组)协作开发而提出来的,为了提高团 ...

  5. Canvas入门(3):图像处理和渲染文本

    资源:http://www.ido321.com/997.html 一.图像处理(非特别说明,全部结果均来自最新版Google) 在HTML 5中,不仅能够使用Canvas API绘制图形,也能够用于 ...

  6. 图文解说PhpStorm 7.0版本语法着色

    前不久,我们测试了PhpStorm7.0版本对PHP 5.5的支持,今天我们将继续对PhpStorm 7.0版本对代码支持进行测试. 我们知道,在PhpStorm 6.0版本中,提供一个黑色背景的代码 ...

  7. vs 文件头自动添加注释

    原文:vs 文件头自动添加注释 vs2010 C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplates ...

  8. hexo github

    win 安装nodejs,用nodejs cmd执行 npm install -g hexo hexo init blog cd blog npm install 或者新建文件夹,进去init再npm ...

  9. [转]当图片源大小大于ImageView大小时的处理方式(缩放)

    转一篇当图片源大小大于ImageView大小定死时的处理方法,但不适用于图片大小小于ImageView时的情况,因为inSampleSize不能<1, 谁有特别好的放大的解决方案,除了设置Ima ...

  10. Web层后端权限模块

    从零开始编写自己的C#框架(19)——Web层后端权限模块   不知不觉本系统写了快三个月了,最近写页面的具体功能时感觉到有点吃力,很多地方如果张嘴来讲的话可以说得很细,很全面,可写成文字的话,就不太 ...