当前位置: 首页 > news >正文

Linux IPC实践(4) --System V消息队列(1)

消息队列概述

   消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限于本机);

   每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值.

   消息队列也有管道一样的不足: (1)每个消息的最长字节数的上限(MSGMAX); (2)系统中消息队列的总条数也有一个上限(MSGMNI); (3)每个消息队列所能够保存的总字节数是有上限的(MSGMNB) .

 

查看系统限制

   cat /proc/sys/kernel/msgmax  #最大消息长度限制

   cat /proc/sys/kernel/msgmnb  #消息队列总的字节数

   cat /proc/sys/kernel/msgmni  #消息条目数

 

 

管道 vs. 消息队列

管道

消息

流管道

有边界

先进先出

可以后进先出

 

IPC对象数据结构

[cpp] view plain copy
  1. //内核为每个IPC对象维护一个数据结构  
  2. struct ipc_perm  
  3. {  
  4.     key_t          __key;       /* Key supplied to msgget(2) */  
  5.     uid_t          uid;         /* Effective UID of owner */  
  6.     gid_t          gid;         /* Effective GID of owner */  
  7.     uid_t          cuid;        /* Effective UID of creator */  
  8.     gid_t          cgid;        /* Effective GID of creator */  
  9.     unsigned short mode;        /* Permissions */  
  10.     unsigned short __seq;       /* Sequence number */  
  11. };  
[cpp] view plain copy
  1. //消息队列特有的结构  
  2. struct msqid_ds  
  3. {  
  4.     struct ipc_perm msg_perm;     /* Ownership and permissions 各类IPC对象所共有的数据结构*/  
  5.     time_t          msg_stime;    /* Time of last msgsnd(2) */  
  6.     time_t          msg_rtime;    /* Time of last msgrcv(2) */  
  7.     time_t          msg_ctime;    /* Time of last change */  
  8.     unsigned long   __msg_cbytes; /* Current number of bytes in queue (nonstandard) 消息队列中当前所保存的字节数 */  
  9.     msgqnum_t       msg_qnum;     /* Current number of messages in queue 消息队列中当前所保存的消息数 */  
  10.     msglen_t        msg_qbytes;   /* Maximum number of bytes allowed in queue 消息队列所允许的最大字节数 */  
  11.     pid_t           msg_lspid;    /* PID of last msgsnd(2) */  
  12.     pid_t           msg_lrpid;    /* PID of last msgrcv(2) */  
  13. };  


消息队列在内核中的表示

 

消息在消息队列中是以链表形式保存的, 每个节点的类型类似如下:

[cpp] view plain copy
  1. struct msq_Node  
  2. {  
  3.     Type msq_type;  //类型  
  4.     Length msg_len; //长度  
  5.     Data msg_data;  //数据  
  6.   
  7.     struct msg_Node *next;  
  8. };  


消息队列API

[cpp] view plain copy
  1. #include <sys/types.h>  
  2. #include <sys/ipc.h>  
  3. #include <sys/msg.h>  
  4. int msgget(key_t key, int msgflg);  
  5. int msgctl(int msqid, int cmd, struct msqid_ds *buf);  
  6. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);  
  7. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);  


msgget

功能:用来创建和访问一个消息队列

[cpp] view plain copy
  1. int msgget(key_t key, int msgflg);  

参数:

  key: 某个消息队列的名字

  msgflg:由九个权限标志构成,如0644,它们的用法和创建文件时使用的mode模式标志是一样的(但是消息队列没有x(执行)权限)

返回值:

  成功返回消息队列编号,即该消息队列的标识码;失败返回-1

 

msgget调用关系图

[cpp] view plain copy
  1. /** 示例1: 在msgflg处指定IPC_CREAT, 如果不存在该消息队列, 则创建之**/  
  2. int main(int argc, char *argv[])  
  3. {  
  4.     //指定IPC_CREAT,如果不存在, 则创建消息队列  
  5.     int msgid = msgget(1234, 0666|IPC_CREAT);  
  6.     if (msgid == -1)  
  7.         err_exit("msgget error");  
  8.     cout << "msgget success" << endl;  
  9. }  
[cpp] view plain copy
  1. /** 示例2:IPC_CREAT|IPC_EXCL, 如果该消息队列已经存在, 则返回出错 **/  
  2. int main(int argc, char *argv[])  
  3. {  
  4.     //指定IPC_EXCL, 如果已经存在,则报告文件已经存在(错误)  
  5.     int msgid = msgget(1234, 0666|IPC_CREAT|IPC_EXCL);  
  6.     if (msgid == -1)  
  7.         err_exit("msgget error");  
  8.     cout << "msgget success" << endl;  
  9. }  
[cpp] view plain copy
  1. /**示例3:将key指定为IPC_PRIVATE(值为0) 
  2. 将key指定为IPC_PRIVATE之后,则msgget就一定会创建一个新的消息队列, 
  3. 而且每次创建的消息队列的描述符都是不同的! 因此, 除非将MessageID(key)传送给其他进程(除非有关联的进程),其他进程也无法使用该消息队列(血缘fork除外) 
  4. 因此, IPC_PRIVATE创建的消息队列,只能用在与当前进程有关系的进程中使用! 
  5. **/  
  6. int main(int argc, char *argv[])  
  7. {  
  8.     //指定IPC_PRIVATE  
  9.     int msgid = msgget(IPC_PRIVATE, 0666|IPC_CREAT|IPC_EXCL);  
  10.     if (msgid == -1)  
  11.         err_exit("msgget error");  
  12.     cout << "msgget success" << endl;  
  13. }  
[cpp] view plain copy
  1. /** 示例4: 仅打开消息队列时, msgflg选项可以直接忽略(填0), 此时是以消息队列创建时的权限进行打开 
  2. **/  
  3. int main(int argc, char *argv[])  
  4. {  
  5.     int msgid = msgget(1234, 0);  
  6.     if (msgid == -1)  
  7.         err_exit("msgget error");  
  8.     cout << "msgget success" << endl;  
  9.     cout << "msgid = " << msgid << endl;  
  10. }  
[cpp] view plain copy
  1. //示例5:低权限创建,高权限打开  
  2. int main()  
  3. {  
  4.     //低权限创建  
  5.     int msgid = msgget(0x255,0444 | IPC_CREAT);  
  6.     if (msgid < 0)  
  7.         err_exit("mesget error");  
  8.     else  
  9.         cout << "Create Mes OK, msgid = " << msgid << endl;  
  10.   
  11.     //高权限打开  
  12.     msgid = msgget(0x255,0644 | IPC_CREAT);  
  13.     if (msgid < 0)  
  14.         err_exit("mesget error");  
  15.     else  
  16.         cout << "Create Mes OK, msgid = " << msgid << endl;  
  17. }  



msgctl函数

功能:获取/设置消息队列的信息

[cpp] view plain copy
  1. int msgctl(int msqid, int cmd, struct msqid_ds *buf);  

参数:

   msqid: 由msgget函数返回的消息队列标识码

   cmd:是将要采取的动作(见下)

 

cmd:将要采取的动作(有三个可取值),分别如下:

[cpp] view plain copy
  1. /** 示例1: IPC_RMID, 删除消息队列 
  2. 注意: 消息队列并没有运用”引用计数”的功能 
  3. **/  
  4. int main()  
  5. {  
  6.     int msgid = msgget(1234, 0);  
  7.     if (msgid == -1)  
  8.         err_exit("msgget error");  
  9.     if (msgctl(msgid, IPC_RMID, NULL) == -1)  
  10.         err_exit("msgctl IPC_RMID error");  
  11.     cout << "msgctl IPC_RMID success" << endl;  
  12. }  
[cpp] view plain copy
  1. /** 示例2: IPC_STAT 
  2. **/  
  3. int main()  
  4. {  
  5.     int msgid = msgget(0x255, 0666|IPC_CREAT);  
  6.     if (msgid == -1)  
  7.         err_exit("msgget error");  
  8.   
  9.     struct msqid_ds buf;  
  10.     if (msgctl(msgid,IPC_STAT,&buf) == -1)  
  11.         err_exit("msgctl error");  
  12.   
  13.     printf("buf.msg_perm.mode = %o\n",buf.msg_perm.mode);   //%o以八进制打印  
  14.     printf("buf.__key = %x\n", buf.msg_perm.__key);         //%x以十六进制打印  
  15.     cout << "buf.__msg_cbytes = " << buf.__msg_cbytes << endl;  
  16.     cout << "buf.msg_qbytes = " << buf.msg_qbytes << endl;  
  17.     cout << "buf.msg_lspid = " << buf.msg_lspid << endl;  
  18. }  
[cpp] view plain copy
  1. /** 实践:IPC_SET,一般需要先获取,然后再设置 
  2. **/  
  3. int main()  
  4. {  
  5.     int msgid = msgget(0x255, 0);  
  6.     if (msgid == -1)  
  7.         err_exit("msgget error");  
  8.   
  9.     //获取消息队列的属性  
  10.     struct msqid_ds buf;  
  11.     if (msgctl(msgid,IPC_STAT,&buf) == -1)  
  12.         err_exit("msgctl error");  
  13.   
  14.     //设置消息队列的属性  
  15.     buf.msg_perm.mode = 0600;  
  16.     if (msgctl(msgid, IPC_SET, &buf) == -1)  
  17.         err_exit("msgctl error");  
  18.   
  19.     //获取并打印  
  20.     bzero(&buf, sizeof(buf));  
  21.     if (msgctl(msgid, IPC_STAT, &buf) == -1)  
  22.         err_exit("msgctl IPC_STAT error");  
  23.     printf("mode = %o\n", buf.msg_perm.mode);  
  24. }  


附-查看系统中的IPC对象

     ipcs

   删除消息队列

     ipcrm -q [msqid]

  或  ipcrm -Q [key] #如果key不等于0的话

转载于:https://www.cnblogs.com/lifan3a/articles/7001912.html

相关文章:

  • CSS的子选择器与后代选择器的区别
  • salt Rosters
  • 14_通过sharedPreferences保存用户名密码
  • codeforces 814D (DFS)
  • [转]eclipse 配置黑色主题 Luna 方式三
  • bootstrap validate remote 自定义message返回
  • e课表项目第二次冲刺周期第十天
  • http 又想起了苑
  • 使用JPA和Hibernate进行批量处理的最佳方式
  • Linux系统下GDB调试
  • 【安卓9】SimpleCursorAdapter、在列表中展示数据
  • 查看windows进程,并删除
  • 阿里云上部署开源PaaS平台Cloud Foundry实战
  • 页码生成算法
  • C++内联函数
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【Leetcode】104. 二叉树的最大深度
  • 【刷算法】从上往下打印二叉树
  • Apache的80端口被占用以及访问时报错403
  • canvas 高仿 Apple Watch 表盘
  • javascript面向对象之创建对象
  • JS+CSS实现数字滚动
  • Making An Indicator With Pure CSS
  • MySQL的数据类型
  • Redis中的lru算法实现
  • zookeeper系列(七)实战分布式命名服务
  • 从零开始在ubuntu上搭建node开发环境
  • 技术:超级实用的电脑小技巧
  • 前言-如何学习区块链
  • 设计模式走一遍---观察者模式
  • 使用SAX解析XML
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 一道面试题引发的“血案”
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • puppet连载22:define用法
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • #HarmonyOS:Web组件的使用
  • #include<初见C语言之指针(5)>
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (1)SpringCloud 整合Python
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (分布式缓存)Redis分片集群
  • (过滤器)Filter和(监听器)listener
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (教学思路 C#之类三)方法参数类型(ref、out、parmas)
  • (蓝桥杯每日一题)love
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (四)模仿学习-完成后台管理页面查询
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • .gitignore文件—git忽略文件
  • .gitignore文件---让git自动忽略指定文件