LINUX下的消息队列实例解析(转)
转载自:http://blog.csdn.net/primeprime/article/details/43323891
目录(?)[+]
一消息队列的基本概念二使用消息队列三消息队列的相关参数消息队列 (也叫做报文队列)是Unix系统V版本中进程间通信机制之一。消息队列就是一个消息的链表。就是把消息看作一个记录,并且这个记录具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读出消息。Linux采用消息队列的方式来实现消息传递。这种消息的发送方式是:发送方不必等待接收方检查它所收到的消息就可以继续工作下去,而接收方如果没有收到消息也不需等待。新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。消息队列是随内核持续的并和进程相关,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构 (struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中中找到访问入口。IPC标识符:每一个I P C目标都有一个唯一的I P C标识符。这里所指的I P C目标是指一个单独的消息队列、一个信号量集或者一个共享的内存段。系统内核使用此标识符在系统内核中指明 I P C目标。IPC关键字:想要获得唯一的标识符,则必须使用一个 I P C关键字。客户端进程和服务器端进程必须双方都同意此关键字。这是建立一个客户机/服务器框架的第一步。一般情况下,可以使用ftok ( )函数为客户端和服务器端产生关键字值。
#include <sys/types.h>
#include<sys/ipc.h>
key_t ftok( const char* fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如: key_t key;
key =ftok(".", 1);
这样就是将fname设为当前目录。id是子序号在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。查询文件索引节点号的方法是: ls -i当删除重建文件后,索引节点号由操作系统根据当时文件系统的使用情况分配,因此与原来不同,所以得到的索引节点号也不同。 如果要确保key_t值不变,要么确保ftok的文件不被删除,要么不用ftok,指定一个固定的key_t值,比如:
#define IPCKEY 0x111
char path[256];
sprintf(path, "%s/etc/config.ini", (char*)getenv("HOME") ); msgid=ftok(path, IPCKEY );
也就是说其实ftok的作用就是根据你所指定的文件的索引点号生成一个独一无二的KEY,并保持。不过在使用的过程中,一般都是直接指定一个固定的值,这样使用起来简单,但一定要确保和其它程序不冲突。
查看一个系统中的消息可以用ipcs –q来查看,这可以看到msgid和权限以及当前有几条消息。当你在调试的过程中,由于程序没有正常结束,而你又想删除此消息时,请使用ipcrm –q msgid命令。
下面结合具体的实例代码详细说明一下使用的过程。
Snd.c文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/stat.h>
#define MAX_TEXT 512
#define MSG_KEY 335
struct my_msg_st
{
long my_msg_type;//这个就是消息的类型,在接收的时候一定要指定这个
//类型才会接收到相应的消息。
char some_text[MAX_TEXT];
};
int main()
{
int i = 10;
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
msgid = msgget((key_t)MSG_KEY, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);//首先创建,如果不成 功,就取得
if(msgid==-1)
{
printf("create faile get imsgid\n");
msgid=msgget((key_t)MSG_KEY,IPC_EXCL|S_IRUSR|S_IWUSR);
}
if (msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
while(running)
{
printf("[%d]Enter some text: less than%d\n",msgid,MAX_TEXT);
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 10;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void*)&some_data, sizeof(some_data), 0) == -1)
{
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if(strncmp(buffer,"end", 3) == 0)
{
running = 0;
}
}
exit(EXIT_SUCCESS);
}
Rcv.c文件
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
#define MSG_KEY 335
struct my_msg_st
{
long my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 10;
msgid =msgget((key_t)MSG_KEY, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
if(msgid==-1)
msgid=msgget((key_t)MSG_KEY,IPC_EXCL|S_IRUSR|S_IWUSR);
if (msgid == -1)
{
fprintf(stderr,"msggetfailed with error: %d\n",errno);
exit(EXIT_FAILURE);
}
printf("prepare receivemsg:%d\n",msgid);
while(running)
{
//这里的msg_to_receive指定了接收消息的类型,如果类型不对,将取不到消息.IPC_NOWAIT 果消息队列里没有消息,则马上返回并设置errno=ENOMSG。如果指定为0则将等待消息的到来。
if (msgrcv(msgid,(void*)&some_data,sizeof(some_data),msg_to_receive,IPC_NOWAIT) == -1)
{
if(ENOMSG==errno)
{
printf("no Msg receive\n");
continue;
}
fprintf(stderr,"msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote:%s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0)
{
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) //使用这个库函数来移除消息队列。
{
fprintf(stderr,"msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);.
}
1.查看系统中默认的消息队列的相关参数
Ipcs –l可以查看当前消息队列的上限限制。
------Messages: Limits --------
max queuessystem wide = 16 2G
max size ofmessage (bytes) = 65536 2G
default maxsize of queue (bytes) = 65536 2G
msgmni最大消息队列数
msgmax最大消息长度(字节数)
msgmnb消息队列中的最大字节数
其实我们要关心的参数主要有三个,说得通俗点就是最多可以有多少个队列使用,每个队列里可以放多少消息,每个消息最多可以带多少内容。
现在解释如下:系统中默认的消息列数是16,最大可以达到2G,系统中消息的个数和消息长度的总数,受队列最大尺寸限制。Msgmnb= msgmax*最大个数.
其中消息队列的长度受结构使用。
structmy_msg_st
{
long my_msg_type;
char some_text[MAX_TEXT];
};
大家如果有兴趣,可以自己写个程序测试试下,简单的很就是无限制分配就可以了。
修改消息队列的参数
1.永久修改
root用户下修改/etc/sysctl.conf文件。
2.临时修改
root用户下sysctl-w kernel.msgmnb= 1048576
/proc/sys/kernel/msgmax 单个消息的最大值
/proc/sys/kernel/msgmnb 单个消息体的容量的最大值
/proc/sys/kernel/msgmni 消息体的数量缺省值为 16
cat/proc/sys/kernel/shmmax
可通过下面的方式进行设置
echo819200 > /proc/sys/kernel/msgmax
echo1638400 > /proc/sys/kernel/msgmnb
echo1600 > /proc/sys/kernel/msgmni
cd /proc/sys/kernel ; cat msgmax;cat msgmnb;cat msgmni;
在程序中可以通过
msgctl(msgid,IPC_STAT,&mymsq_ds);
printf("%d,%d,%d\n",mymsq_ds.msg_qbytes,mymsq_ds.msg_qnum,mymsq_ds.msg_cbytes);来获得队列消息的总大小,已经有的消息数和所占空间数。
1.IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中;
2.IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。
3.IPC_RMID:删除msqid标识的消息队列。
顶 0 踩 0 上一篇linux消息队列函数(转) 下一篇网络编程原始套接字(转) 相关文章推荐 • linux 消息队列实例 (转) • 游戏服务器结构探讨 • Linux内核分析(转自某大牛) • python 常用类库!(转) • Linux下消息队列和socket绝对速度比拼[转] • Linux内核专题 - 介绍 • Linux内核配置选项简介 • Linux进程间通信 之 消息队列(转) • 转:Andriod Phone模块相关 • VLC框架分析