一、    概念

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

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. InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布

    原文:InstallShield集成安装MSDE2000最小版本(一) fishout特许授权发布 原帖地址:http://blog.csdn.net/fishout/archive/2009/10/ ...

  2. Angular指令(一)

    Angular开发者手册重点翻译之指令(一) 创建自定义的指令 这个文章将解释什么需要在自己的angularjs应用中创建自己的指令,以及如何实现它. 什么是指令 在高的层面上讲,指令是DOM元素中的 ...

  3. NFTS数据流

    NFTS数据流 NTFS交换数据流(alternate data streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每一个文件都能够存在多个数据流,就是说除了主文件流之外 ...

  4. iOS_1_加法器

    : BeyondViewController.h // // BeyondViewController.h // 01_calc // // Created by beyond on 14-7-20. ...

  5. WinXP 无线技巧“区域没有通过无线网络中的发现”一个可能的原因!

    貌似WinXP经典或无限.我一直沿用至今,我不知道这一天会放弃. 遇到的问题,也许有XP爱好者都遇到过还得看,写下一点文字注释.----------------------- 切割线 -------- ...

  6. Android在View拉丝工艺和invalidate()和其他相关方法

      转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 . ...

  7. 【C#版本详情回顾】C#3.0主要功能列表

    隐式类型的本地变量和数组 在与本地变量一起使用时,var 关键字指示编译器根据初始化语句右侧的表达式推断变量或数组元素的类型 对象初始值设定项 支持无需显式调用构造函数即可进行对象初始化 集合初始值设 ...

  8. 第三方控件netadvantage UltraWebGrid如何生成多级跨行表头个人总结

    1.生成多级表头,横向和纵向跨度. 1>对于有字段的的表头合并:也就是(工期.项目经理信息除外)可以在前台通过spanx和spany属性控制.对于空字段(工资.项目经理必须通过后台动态添加),而 ...

  9. Git的使用学习资源

    开学第一天一般都挺认真的,认真做个功课. 跟据Ryan Tang的推荐,有两个比较好的学习Git的网站:http://git.gitcafe.com/book/zh 还有一个是CodeSchool的一 ...

  10. TeamCity vs Jenkins: Which is the Better Continuous Integration (CI) Server for .NET Software Development?

    原文:http://www.excella.com/insights/teamcity-vs-jenkins-better-continuous-integration-server So, you’ ...