`
yidongkaifa
  • 浏览: 4063887 次
文章分类
社区版块
存档分类
最新评论

消息队列状态:struct msqid_ds

 
阅读更多

Linux的消息队列(queue)实质上是一个链表, 它有消息队列标识符(queue ID). msgget创建一个新队列或打开一个存在的队列; msgsnd向队列末端添加一条新消息; msgrcv从队列中取消息, 取消息是不一定遵循先进先出的, 也可以按消息的类型字段取消息.


1. 标识符(des)和键(key):


消息队列, 信号量和共享存储段, 都属于内核中的IPC结构, 它们都用标识符来描述. 这个标识符是一个非负整数, 与文件描述符不同的是, 创建时并不会重复利用通过删除回收的整数, 而是每次+1, 直到整数最大值回转到0.


标识符是IPC对象的内部名, 而它的外部名则是key(键), 它的基本类型是key_t, 在头文件<sys/types.h>中定义为长整型. 键由内核变换成标识符.


2. 消息队列状态msqid_ds:


每个消息队列都有一个msqid_ds结构与其关联:




struct 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 */
};




3. 由路径名和项目ID产生一个key:


如果客户进程和服务器进程认同一个路径名和项目ID(0~255间的字符值), 接着调用ftok将这两个值变换为一个key.


原型: key_t ftok(const char *path, int id);
头文件: <sys/ipc.h>
返回值: 成功则返回key, 出错则返回(key_t)-1.
参数: path参数必须引用一个现存文件. 当产生key时 只使用id参数的低8位.
说 明: 如果两个路径名引用两个不同的文件, 对这两个路径名调用ftok通常返回不同的key. 但是, 因为i节点号和key通常存放在长整型中, 于是创建key时可能会丢失信息. 这意味着, 如果使用同一项目ID, 那么对于不同文件的两个路径名可能产生相同的key. 该函数的工作方式为:
按给定的路径名取得其stat结构.
从该结构中取出部分st_dev和st_ino字段, 与项目ID组合起来.
4. 创建/打开消息队列:


msgget可以创建一个新队列或打开一个存在的队列.


原型: int msgget(key_t key, int flag);
头文件: <sys/msg.h>
返回值: 成功则返回消息队列ID, 出错则返回-1.
参数:
key: 消息队列的key值.
flag: 标志位.
说明:
创建队列有两种方法:
key是IPC_PRIVATE.
key当前未与特定类型的IPC结构相结合, 并且flag中指定了IPC_CREAT位.
初始化msqid_ds成员:
ipc_perm中的mode成员按flag进行设置.
msg_qnum, msg_lspid, msg_lrpid, msg_stime和msg_rtime都设置为0.
msg_ctime设置为当前时间.
msg_qbytes设置为系统限制值.
5. 消息队列的垃圾桶函数:


msgctl类似于驱动程序中的ioctl函数, 可对消息队列执行多种操作.


原型: int msgctl(int msqid, int cmd, struct msgqid_ds *buf);
头文件: <sys/msg.h>
返回值: 成功则返回0, 出错则返回-1.
参数: cmd参数说明对msqid指定的队列要执行的命令:
IPC_STAT: 取此队列的msqid_ds结构, 并将它存放在buf指向的结构中.
IPC_SET: 按由buf指向结构中的值, 设置与此队列相关结构中的msg_perm.uid, msg_perm.gid, msg_perm.mode和msg_qbytes. 该命令只有下列两种进程可以执行:
有效用户ID等于msg_perm.cuid或msg_per.uid.
具有超级用户特权的进程.
IPC_RMID: 从系统中删除该消息队列以及仍在该队列中的所有数据. 执行权限同上.
6. 将数据放到消息队列:


调用msgsnd将数据放到消息队列中.


原型: int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
头文件: <sys/msg.h>
返回值: 成功则返回0, 出错则返回-1.
说 明: 可以定义一个消息结构, 结构中带类型, 这样就可用非先进先出顺序取消息了. 当msgsnd成功返回, 与消息队列相关的msqid_ds结构得到更新, 以标明发出该调用的进程ID(msg_lsqid), 进行该调用的时间(msg_stime), 并指示队列中增加了一条消息(msg_qnum).
7. 从消息队列中取消息:


调用msgrcv将从消息队列中取消息.


原型: ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
头文件: <sys/msg.h>
返回值: 成功则返回消息的数据部分的长度, 出错则返回-1.
参数:
ptr: 指向一个长整型数(返回的消息类型存放在其中), 跟随其后的是存放实际消息数据的缓冲区.
nbytes: 数据缓冲区的长度. 若返回的消息大于nbytes, 且在flag中设置了MSG_NOERROR, 则该消息被截短.
type:
type == 0: 返回队列中的第一个消息.
type > 0: 返回队列中消息类型为type的第一个消息.
type < 0: 返回队列中消息类型值小于或等于type绝对值的消息, 如果这种消息有若干个, 则取类型值最小的消息.
说明: 当msgrcv成功返回时, 与消息队列相关的msqid_ds结构被更新, 以指示调用者的进程ID(msg_lrpid), 调用时间(msg_rtime)和队列中的消息数(msg_qnum)减1.
四、消息队列应用实例
消息队列应用相对较简单,下面实例基本上覆盖了对消息队列的所有操作,同时,程序输出结果有助于加深对前面所讲的某些规则及消息队列限制的理解。


#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
void msg_stat(int,struct msqid_ds );
main()
{
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);
if(msgid==-1)
{
printf("msg create error\n");
return;
}
//创建一个消息队列后,输出消息队列缺省属性
msg_stat(msgid,msg_ginfo);
sflags=IPC_NOWAIT;
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a';
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
if(reval==-1)
{
printf("message send error\n");
}
//发送一个消息后,输出消息队列属性
msg_stat(msgid,msg_ginfo);
rflags=IPC_NOWAIT|MSG_NOERROR;
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
if(reval==-1)
printf("read msg error\n");
else
printf("read from msg queue %d bytes\n",reval);
//从消息队列中读出消息后,输出消息队列属性
msg_stat(msgid,msg_ginfo);
msg_sinfo.msg_perm.uid=8;//just a try
msg_sinfo.msg_perm.gid=8;//
msg_sinfo.msg_qbytes=16388;
//此处验证超级用户可以更改消息队列的缺省msg_qbytes
//注意这里设置的值大于缺省值
reval=msgctl(msgid,IPC_SET,&msg_sinfo);
if(reval==-1)
{
printf("msg set info error\n");
return;
}
msg_stat(msgid,msg_ginfo);
//验证设置消息队列属性
reval=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(reval==-1)
{
printf("unlink msg queue error\n");
return;
}
}
void msg_stat(int msgid,struct msqid_ds msg_info)
{
int reval;
sleep(1);//只是为了后面输出时间的方便
reval=msgctl(msgid,IPC_STAT,&msg_info);
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);
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
printf("last msgsnd time is %s", ctime(&(msg_info.msg_stime)));
printf("last msgrcv time is %s", ctime(&(msg_info.msg_rtime)));
printf("last change time is %s", ctime(&(msg_info.msg_ctime)));
printf("msg uid is %d\n",msg_info.msg_perm.uid);
printf("msg gid is %d\n",msg_info.msg_perm.gid);
}
分享到:
评论

相关推荐

    C++11模板元编程-std::enable_if示例详解

    struct enable_if; 可能的函数实现: template struct enable_if {}; template struct enable_if&lt;true&gt; { typedef T type; }; 由上可知,只有当第一个模板参数为true时,enable_if会包含一个type=T的公有成员,...

    Micro::racing_car:快速差异化并为UICollectionView键入安全的SwiftUI样式数据源

    只是声明了一个State与SwiftUI风格forEach和Micro将与动画版本比较重装struct Blog : DiffAware {}class BlogCell : UICollectionViewCell {}let dataSource = DataSource ( collectionView : collectionView)...

    vc++6.0操作系统进程调度

    在操作系统中,关于进程调度的程序,采用了优先和时间片的两个算法。

    caffe分类器动态库编译

    动态库编译好了,提供dll,lib,.h.以及测试代码、只需要自己的训练的分类器,网络结构均值,类别就可以试用了

    live555 centos 64位修改编译报错

    直接从官网下载的live555源码在centos 64位下编译报错,此为修改后版本。

    e1000e-3.8.4.tar.gz

    Intel的型号是I219-LM。但是这个型号在Intel官网上只有FreeBSD的驱动,并没有Linux的源码。 后面又发现了www.centos.org上的内容,确认了可以和e1000e的网卡驱动通用

    c++11 mem_fn

    函数模板 std::mem_fn 生成指向成员指针的包装对象,它可以...struct int_holder { int value; int triple() { return value * 3; } }; int main() { int_holder five{ 5 }; std::cout &lt;&lt; five.triple() &lt;

    struct2_jar

    struct2_jar完整包,用于web或服务器端开发

    carmanage.rar_MANAG車_carmanage_struct java_struct mysql_汽车租赁

    汽车租赁管理系统简单代码,基于myeclipse+mysql+struct的可运行的代码,注意发布和建库。

    solve_ROPF_MAXkshunts_MAXkmoves.jl

    struct ROPF_infos instance_name::String matpower_instance_path::String output_instance_path::String decomposition::String output_decomposition_path::String end 示例: instance_name = "case1888rte" ...

    智能指针shared-ptr的用法.pdf

    智能指针 智能指针shared_ptr的⽤法 的⽤法 为了解决C++内存泄漏的问题,C++11引⼊了智能指针(Smart Pointer)。 智能指针的原理是,接受⼀个申请好... struct AStruct { std::shared_ptr&lt;BStruct&gt; bPtr; ~AStruct() {

    iTunesMobileDevice.dll开发文档API文档

    回调函数,当设备状态改变时由iTunesMobileDevice.dll回调 参数: am_device_notification_callback_info 返回设备信息 am_restore_device_notification_callback 定义: typedef void (*am_restore_device_...

    在C++中侦测内嵌型别的存在.doc

    struct student_tag{}; struct teacher_tag{}; 还有Register的几个供内部使用的重载版本: template&lt;class T&gt; void Register(T p,student_tag){...} //注册学生 template&lt;class T&gt; void Register(T p,teacher_...

    ConcreteStructs.jl::love_hotel::house::cityscape_at_dusk::hotel::sunset::bank:

    @concrete struct AB a b end julia&gt; ab = AB("hi", 1+im) AB{String,Complex{Int64}}("hi", 1 + 1im) 宏还支持terse关键字,以使类型在IOContext :compact =&gt; true模式下不带参数即可显示。 @concrete terse ...

    config_loader:Message Queue配置加载程序类型结构

    msqueue_config_loader 定义消息队列配置结构并实现LoadByFile和LoadByBytes接口。 type QueueConfig struct {Url string `json:"url" yaml:"url"`AccessKeyId string `json:"access_key_id" yaml:"access_key_id"`...

    工资管理系统c语言

    员工工资管理系统,数据结构:struct Salary_Info{ char Card_No[20]; //工资卡号 char name[20]; //姓名 int month; //月份 float Init_Salary; //应发工资 float Water_Rate; //水费 float Electric_Rate;...

    标准MFC WinSock ActiveX控件开发实例

    重载控件消息处理函数WindowProc(),在View-&gt;ClassWizard中打开类向导,在消息映射中找到WindowProc,如下图: 图五 重载WindowProc() 四、编写代码 编写VariantToLong()转换函数,该函数代码如下: //类型转换,将...

    DataStruct_Queue

    DataStruct_Queue 数据结构队列代码,C++实现

    pid_task_struct_pid_link.docx

    内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数内核进程命名空间函数

    iOS.Blog.SwiftUI_Search_Bar_in_Navigation_Bar::magnifying_glass_tilted_left:导航栏中的SwiftUI搜索栏

    struct ContentView : View{ var planets = [ " Mercury " , " Venus " , " Earth " , " Mars " , " Jupiter " , " Saturn " , " Uranus " , " Neptune " ] + [ " Ceres " , " Pluto " , " Haumea " , " Makemake ...

Global site tag (gtag.js) - Google Analytics