您的位置:首页 > 运维架构 > Linux

Linux编程实践----消息队列的演示(IPC)

2014-05-23 10:16 393 查看
Linux编程实践----消息队列的演示(IPC)
1.消息队列(Message queue)----是一种在两个不相关的进程间的通信方式。特点就是消息的发送者以及接受者不需要同时与消息队列互动。消息会保存在队列中,直到接受者取回它。
2.实现:消息队列常常保存在链表的结构中。拥有权限的进程可以向消息队列中写入或读取消息。
3.是一种异步通信协议;与信号相比,消息队列可以传递更多的东西!与管道相比,消息队列提供了有格式的数据

4.系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(struct ipc_ids msg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中找到访问入口。
5.系统V消息队列API:
(1)int msgget(key_t key, int msgflg)
参数key是一个键值,由ftok获得;msgflg参数是一些标志位。该调用返回与健值key相对应的消息队列描述字。

在以下两种情况下,该调用将创建一个新的消息队列:

如果没有消息队列与健值key相对应,并且msgflg中包含了IPC_CREAT标志位;
key参数为IPC_PRIVATE;

参数msgflg可以为以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果。

调用返回:成功返回消息队列描述字,否则返回-1。

注:参数key设置成常数IPC_PRIVATE并不意味着其他进程不能访问该消息队列,只意味着即将创建新的消息队列。

(2)int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);

该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。
msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读消息标志msgflg可以为以下几个常值的或:

IPC_NOWAIT 如果没有满足条件的消息,调用立即返回,此时,errno=ENOMSG
IPC_EXCEPT 与msgtyp>0配合使用,返回队列中第一个类型不为msgtyp的消息
IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将丢失。

msgrcv手册中详细给出了消息类型取不同值时(>0; <0; =0),调用将返回消息队列中的哪个消息。

msgrcv()解除阻塞的条件有三个:

消息队列中有了满足条件的消息;
msqid代表的消息队列被删除;
调用msgrcv()的进程被信号中断;

调用返回:成功返回读出消息的实际字节数,否则返回-1。

(3)int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);

向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。
对发送消息来说,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。造成msgsnd()等待的条件有两种:

当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量;
当前消息队列的消息数(单位"个")不小于消息队列的总容量(单位"字节数"),此时,虽然消息队列中的消息数目很多,但基本上都只有一个字节。

msgsnd()解除阻塞的条件有三个:

不满足上述两个条件,即消息队列中有容纳该消息的空间;
msqid代表的消息队列被删除;
调用msgsnd()的进程被信号中断;

调用返回:成功返回0,否则返回-1。

(4)int msgctl(int msqid, int cmd, struct msqid_ds *buf);

该系统调用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中;
IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。
IPC_RMID:删除msqid标识的消息队列;

调用返回:成功返回0,否则返回-1。

6.消息队列的限制:每个消息队列的容量(所能容纳的字节数)都有限制,该值因系统不同而不同。另一个限制是每个消息队列所能容纳的最大消息数。系统对消息队列的限制还有系统范围内的最大消息队列个数,以及整个系统范围内的最大消息数。一般来说,实际开发过程中不会超过这个限制。

7.总结:消息队列与管道以及有名管道相比,具有更大的灵活性,首先,它提供有格式字节流,有利于减少开发人员的工作量;其次,消息具有类型,在实际应用中,可作为优先级使用。

示例演示:lovemsg2发送消息四次,然后运行lovemsg1接收消息。其中代码lovemsg2仅作为示例代码,未考虑失败的情形。
1.发送的数据结构:lovemessage.h
struct lovemsg
{
long int type;
char text[100];
};
~


2.接受消息的代码:lovemsg1.cpp

#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<iostream>
#include<string.h>
#include<sys/msg.h>
#include"lovemessage.h"
using namespace std;

int main()
{
cout<<"MSG1 is running!"<<endl;
int running=1;
//Create a message queue
int msgid=msgget((key_t)1314,0666 | IPC_CREAT);
if(msgid==-1)
{
cout<<"msgget failed! "<<errno<<endl;
exit(EXIT_FAILURE);
}
//Get Message
lovemsg lovemessage;
long int receive=0;
int times=0;
while(running)
{
if(-1==msgrcv(msgid,(void *)&lovemessage,100,receive,0))
{
cout<<"msgrcv failed "<<errno;
exit(EXIT_FAILURE);
}
cout<<"MSG1 receive :"<<lovemessage.text<<endl;
times++;
if(3<times)
running=0;
}
//Remove message queue
if(-1==msgctl(msgid,IPC_RMID,0))
{
cout<<"msgctl failed"<<endl;
exit(EXIT_FAILURE);
}

exit(EXIT_SUCCESS);
}
~


3.发送消息的代码:lovemsg2.cpp

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<iostream>
#include<string.h>
#include<sys/msg.h>
#include"lovemessage.h"
using namespace std;

int main()
{
cout<<"MSG2 is running!"<<endl;
int running=1;
int msgid=msgget((key_t)1314,0666 | IPC_CREAT);
lovemsg lovemessage;
int times=0;
while(running)
{
cout<<"Enter love message:"<<endl;
fgets(lovemessage.text,100,stdin);
lovemessage.type=1;
msgsnd(msgid,(void *)&lovemessage,100,0);
times++;
if(3<times)
running=0;

}
}
~


4.编译并运行,结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: