消息队列的创建与读写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可以实现微信(好友或微信群)的信息处理,包括文本.图片.小 ...
随机推荐
- 用Nodejs连接MySQL(原文链接)
原文链接:http://blog.fens.me/nodejs-mysql-intro/
- ubuntu服务器 安装 seafile 个人网盘
目录 ubuntu服务器 安装 seafile 个人网盘 一.实验环境: 二.实验流程介绍 三.网盘搭建 1.安装依赖环境 2.安装seafile 三.配置QQ域名邮箱 四.配置seafile邮件服务 ...
- 使用libcurl开源库和Duilib做的下载文件并显示进度条的小工具
转载:http://blog.csdn.net/mfcing/article/details/43603525 转载:http://blog.csdn.net/infoworld/article/de ...
- CEF解决加载慢问题
转载:http://blog.csdn.net/weolar/article/details/51994895 CEF加载慢的时候,加上以下代码,通过命令行的方式: CefRefPtr<CefC ...
- 字符串分割(C++)(转载)
转载出自:http://www.cnblogs.com/MikeZhang/archive/2012/03/24/MySplitFunCPP.html 经常碰到字符串分割的问题,这里总结下,也方便我以 ...
- Java DecimalFormat 用法(数字格式化)
我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供 DecimalFormat 类,帮你用最快的速度将数字格式化为你需要的样子.下面是常用的例子: import java.tex ...
- 51NOD 1099 任务执行顺序
来源:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1099 前天没睡好 昨天做题闷闷沉沉的 好多一眼题 都瞎做了 这题今 ...
- BZOJ2982: combination Lucas
Description LMZ有n个不同的基友,他每天晚上要选m个进行[河蟹],而且要求每天晚上的选择都不一样.那么LMZ能够持续多少个这样的夜晚呢?当然,LMZ的一年有10007天,所以他想知道答案 ...
- 用caffe进行图片检索
1.图片的处理 输入:将自己的图像转换成caffe需要的格式要求:lmdb 或者 leveldb 格式 这里caffe有自己提供的脚本:create_minst.sh 转换训练图片和验证图片的格式,运 ...
- ng-model 数据不更新 及 ng-repeat【ngRepeat:dupes】错误
一.ng-include 引入的文件中 ,ng-model 数据不更新 例如, $scope.username = “Jones” .此时,在 ng-include 引入的文件中,直接使用 ng-m ...