消息队列的创建与读写ftok,msgget,msgsnd,msgrcv,指令ipcs,ipcrm 查看,删除消息队列
ipcs是Linux下显示进程间通信设施状态的工具。可以显示消息队列、共享内存和信号量的信息。对于程序员非常有用,普通的系统管理员一般用不到此指令。
ipcs -q 查看系统使用的IPC队列资源
ipcs -m 查看系统使用的IPC共享内存资源
ipcs -s 查看系统使用的IPC信号量资源
ipcs -a命令可以查看当前使用的共享内存、消息队列及信号量所有信息
ipcs -p命令可以得到与共享内存、消息队列相关进程之间的消息
ipcs -u命令可以查看各个资源的使用总结信息,其中可以看到使用的信号量集的个数、信号量的个数,
以及消息队列中当前使用的消息个数总数、占用的空间字节数。
默认不加参数时,使用的参数是 -a (all,显示所有)
pcs -l命令可以查看各个资源的系统限制信息,可以看到系统允许的最大信号量集及信号量个数限制、最大的消息队列中消息个数等信息。
yxg@k8s:~$ ipcs -l
------ Messages Limits --------
max queues system wide = 32000 //系统最多的消息队列数量
max size of message (bytes) = 8192 //单个消息的最大字节数
default max size of queue (bytes) = 16384 //单个消息的最大字节数
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1
------ Semaphore Limits --------
max number of arrays = 32000
max semaphores per array = 32000
max semaphores system wide = 1024000000
max ops per semop call = 500
semaphore max value = 32767
这个限制可以通过增加内核参数 semmni 的取值来解决,该参数定义了系统能够拥有的信号量集合的
总数。Linux 可以动态调整大多数内核IPC 参数值的大小,也可以静态地修改
1、创建消息队列
消息队列是随着内核的存在而存在的,每个消息队列在系统范围内对应唯一的键值。要获得一个消息队列的描述符,
只需要提供该消息队列的键值即可,该键值通常由函数ftok返回。
key_t ftok(const char *pathname, int proj_id);
ftok函数根据pathname和proj_id这两个参数生成唯一的键值。
pathname:must refer to an existing, accessible file,在系统中一定要存在,且进程有访问权限。
proj_id:的取值范围为1-255
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h> int main()
{ int i = ;
for(i=;i<;i++)
{
printf("key[%d] = %lu\n", i, ftok(".", i));
} return ;
}
ftok返回的键值可以提供给函数msgget,
msgget根据这个键值创建一个新的消息队列或者访问一个已存在的消息队列。
int msgget(key_t key, int msgflg);
参数key即为ftok函数的返回值。msgflag是一个标志参数。
以下是msgflg的可能取值:
IPC_CREAT:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回消息队列的描述符。
IPC_EXCL:和IPC_CREAT一起使用,如果对应键值的消息队列已经存在,则出错,返回-1
上述msgflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定消息队列的存取权限.
如果用msgget创建了一个新的消息队列对象时,则msqid_ds结构成员变量的值设置如下:
msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime设置为0。
msg_ctime设置为当前时间。
msg_qbytes设成系统的限制值。
msgflg的读写权限写入msg_perm.mode中。
msg_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
注意:IPC_EXCL单独使用是没有任何意义的。
该函数如果调用成功返回一个消息队列的描述符,否则返回-1
2、写消息队列
创建了一个消息队列后,就可以对消息队列进行读写了。函数msgsnd用于向消息队列发送(写)数据。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msqid:函数向msgid标识的消息队列发送一个消息
msgp:指向发送的消息。
msgsz:要发送消息的大小,不包含消息类型占用的4个字节。
msgflg:操作标识位。可以设置为0或者IPC_NOWAIT。如果为0,则当消息队列已满的时候,msgsnd将会阻塞,直到消息可写进消息队列;如果msgflg
为IPC_NOWAIT,当消息队列已满的时候,msgsnd函数将不等待立即返回。
msgsnd函数成功返回0,失败返回-1。常见错误码有:EAGAIN,说明消息队列已满。
EIDRM:说明消息队列已被删除
EACCES:说明无权访问消息队列
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h> //用户自定义消息缓冲
struct mymsgbuf{
long msgtype;
char buf[];
}; int main()
{
struct mymsgbuf mymsgbuffer;
int msglen = ;
int i = ;
int msgkey = ; int qid = ;//消息队列标识符 //获取键值
msgkey = ftok(".", ); qid = msgget(msgkey, IPC_CREAT|);
printf("msgget return %d\n", qid); //填充消息结构,发送到消息队列
mymsgbuffer.msgtype = ;
strcpy(mymsgbuffer.buf, "manman");
msglen = sizeof(struct mymsgbuf) - ; if (msgsnd(qid, &mymsgbuffer, msglen, ) == -)
{
perror("msgsnd error\n");
exit();
} return ;
}
root@wilson-software:~/Project/xa# ./main
msgget return 0
执行程序之后,就向消息队列放入了一条消息,通过指令ipcs查看:
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 256 1
3、读消息队列
消息队列中放入数据后,其他进程就可以读取其中的消息了。读取消息的系统调用为
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数含义:
msqid:消息队列描述符
msgp:读取的消息存储到msgp指向的消息结构中
msgsz:消息缓冲区的大小
msgtyp:为请求读取的消息类型
msgflg:操作标志位。msgflg可以为IPC_NOWAIT, MSG_EXCEPT ,MSG_NOERROR
0:表示忽略
IPC_NOWAIT:如果没有满足条件的消息,调用立即返回,此时错误码为ENOMSG
如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的
消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回如果进
程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。
MSG_EXCEPT :与msgtype配合使用,返回队列中第一个类型不为msgtype的消息
MSG_NOERROR:如果队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将被丢弃。
如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被
取出。当消息从队列内取出后,相应的消息就从队列中删除了。
可利用ipcrm -q 294912删除该消息队列。(294912为msgqid)因为消息队列是随内核持续存在的,在程序中若不利用msgctl函数或在命令行用ipcrm命令显式地删除,该消息队列就一直存在于系统中。另外信号量和共享内存也是随内核持续存在的
在读取前:
------ Message Queues --------
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 256 1
在读取后
key msqid owner perms used-bytes messages
0x0b014424 0 root 660 0 0
调用msgrcv函数的时候,成功会返回读出消息的实际字节数,否则返回-1。
常见错误码有:
E2BIG: 表示消息的长度大于msgsz
EIDRM:表示消息队列已被删除
EINVAL:说明msgqid无效或msgsz小于0
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdlib.h>
#include <string.h> //用户自定义消息缓冲
struct mymsgbuf{
long msgtype;
char buf[];
}; int main()
{
struct mymsgbuf mymsgbuffer;
int msglen = ;
int i = ;
int msgkey = ; int qid = ;//消息队列标识符 //获取键值
msgkey = ftok(".", ); qid = msgget(msgkey, IPC_CREAT|);
printf("msgget return %d\n", qid); msglen = sizeof(struct mymsgbuf) - ;
//上面的程序中发送的消息类型是4
//注意,msgrcv的msgflg参数可设置msgrcv函数是否是阻塞的,经测试msgflg是0的情况会阻塞,直到获取到消息
if (msgrcv(qid, &mymsgbuffer, msglen, 4, ) == -)
{
perror("msgsnd error\n");
exit();
} printf("get message:%s\n", mymsgbuffer.buf); return ;
}
运行结果:
root@wilson-software:~/Project/xa# ./main
msgget return 0
get message:manman
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
利用上面提到的msgrcv()对消息长度的处理,我们可以使用下面的方法来检查队列内
是存在符合条件的信息:
int peek_message( int qid, long type )
{
int result, length;
if((result = msgrcv( qid, NULL, 0, type, IPC_NOWAIT)) == -1)
{
if(errno == E2BIG)
return(TRUE);
}
return(FALSE);
}
这里我们将msgp 和msgsz 分别设为NULL 和零。然后检查函数的返回值,如果是E2BIG
则说明存在符合指定类型的消息。一个要注意的地方是IPC_NOWAIT 的使用,它防止了阻塞
消息队列的创建与读写ftok,msgget,msgsnd,msgrcv,指令ipcs,ipcrm 查看,删除消息队列的更多相关文章
- 获取和设置消息队列的属性msgctl,删除消息队列
消息队列的属性保存在系统维护的数据结构msqid_ds中,用户可以通过函数msgctl获取或设置消息队列的属性. int msgctl(int msqid, int cmd, struct msqid ...
- 消息队列实现回射客户/服务器和 msgsnd、msgrcv 函数
一.msgsnd 和 msgrcv 函数 #include <sys/types.h> #include <sys/ipc.h> #include <sys/ms ...
- SpringCloud系列十一:SpringCloudStream(SpringCloudStream 简介、创建消息生产者、创建消息消费者、自定义消息通道、分组与持久化、设置 RoutingKey)
1.概念:SpringCloudStream 2.具体内容 2.1.SpringCloudStream 简介 SpringCloudStream 就是使用了基于消息系统的微服务处理架构.对于消息系统而 ...
- 消息队列:快速上手ActiveMQ消息队列的JMS方式使用(两种模式:Topic和Queue的消息推送和订阅)
1.实现功能 希望使用一套API,实现两种模式下的消息发送和接收功能,方便业务程序调用 1.发送Topic 2.发送Queue 3.接收Topic 4.接收Queue 2.接口设计 根据功能设计公共调 ...
- PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)
源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...
- Guava缓存器源码分析——删除消息
Guava缓存器的删除消息机制 测试代码—— LoadingCache<String, Integer> cache = CacheBuilder.newBuild ...
- VC2008中如何为MFC应用程序添加和删除消息响应函数
最近重温<MFC Windows应用程序设计>第二版这本书,里面的代码全部是使用VC6.0写的,我Win7下安装的是VS2008开发环境. VC2008下添加和删除常见的消息响应函数有两种 ...
- oracle创建表之前判断表是否存在,如果存在则删除已有表
Mysql 创建表之前判断表是否存在,如果存在则删除已有表 DROP TABLE IF EXISTS sys_area; CREATE TABLE sys_area ( id int NOT NULL ...
- python查看微信消息撤回
准备环境 python语言环境 python解释器-pycharm itchat介绍 itchat是一个开源的微信个人号接口,通过itchat可以实现微信(好友或微信群)的信息处理,包括文本.图片.小 ...
随机推荐
- troubleshooting-windows 在 CDH集群环境读取 Hive 表 KrbException: Cannot locate default realm
KrbException: Cannot locate default realm 解决办法 1)拷贝需要组件的配置文件到项目中的 /resources/目录.如hadoop,目录/etc/hadoo ...
- kafka调试遇到的问题
在三台机器上以不同的端口部署了三个kafka和zookeeper实例,对应三套环境. 如: zk1:2181 zk2:2182 zk3:2183 kafka1:9092 kafka2:9093 kaf ...
- 01: shell基本使用
目录: 1.1 编写登录欢迎脚本 1.2 重定向与管道操作 1.3 使用shell变量 1.4 特殊的shell变量 1.5 read与echo使用比较 1.1 编写登录欢迎脚本返回顶部 (1)新建脚 ...
- sbt介绍与构建Scala项目
一.sbt简介 sbt是类似ANT.MAVEN的构建工具,全称为Simple build tool,是Scala事实上的标准构建工具. 主要特性: 原生支持编译Scala代码和与诸多Scala测试框架 ...
- ArrayList初始化的4种方法
In the last post we discussed about class ArrayList in Javaand it’s important methods. Here we are s ...
- HDU 1247 Hat’s Words(字典树)题解
题意:给一个字符串集,要你给出n个字符串s,使s能被所给字符串集中的两个相加所得(ahat=a+hat) 思路:简单字典树题,注意查询的时候要判断所指next是否为NULL,否则会RE非法访问. 代价 ...
- 【命令】Linux常用命令
常用指令 ls 显示文件或目录ls -f 查看目录中的文件 ls -l 列出文件详细信息l(list) ls -a 列出当前目录下所有文件及目录,包括隐藏的a(all)ls *[0-9]* 显示包含数 ...
- dp暑假专题 训练记录
A 回文串的最小划分 题意:给出长度不超过1000的字符串,把它分割成若干个回文字串,求能分成的最少字串数. #include <iostream> #include <cstdio ...
- c# &与&& 和 |与||的区别
&:按位与,对两个条件都进行判断 &&:逻辑与,只要一个条件满足,另外一个条件就不会执行 同理: |:按位或,对两个条件都进行判断 ||:逻辑或,只要一个条件满足,另外一个条件 ...
- [BZOJ1103][POI2007]大都市meg dfs序+树状数组
Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n ...