linux下消息队列创建,C++封装Linux消息队列

消息队列是Linux进程间通信方式之一,在面向对象编程中,需要对其封装。

一、消息队列的特点

1、异步通信,消息队列会保存进程发送的消息,其他进程不一定要及时取走消息。

2、可以发送不同类型的消息,消息的头部用long类型的字段标记。

3、取消息时,不一定按先进先出的方式,可以按消息的类型来取。

4、消息队列内部是用一个链表来保存消息,当消息被取走后,这个消息就从链表中删除了,而且这个链表的长度

是有限制的,当消息存满后,不能再存入消息。

二、msgid和关键字

消息队列在内核中,要用一个非负整数来标记(类似于描述符或者句柄),这个非负整数称作msqid,即消息

队列的ID,但是要创建或者打开一个消息队列需要一个关键字,这个关键字其实是一个长整型数据。在进程

通信时,必须要约定使用同一个关键字,这样就可以得到同一个消息队列,因为消息队列是由内核维护的,

不同的进程使用相同关键字打开或者创建的消息队列,获得的msgid是相同的。

本例中使用一个文件路径加上课题ID(0~255)调用ftok函数产生一个关键字。

代码如下:

CMsgQueue.h

/*************************************************************************

> File Name: CMsgQueue.h

> Author: KentZhang

> Mail: zhchk2010@qq.com

> Created Time: Wed 02 Sep 2015 08:10:35 PM CST

************************************************************************/

#ifndef _CLASSES_CMSGQUEUE_H__

#define _CLASSES_CMSGQUEUE_H__

#include

#include

#include

#include

#include

#include

#include

#include

#include

//封装消息队列

class CMsgQueue

{

public:

CMsgQueue(const char* path, int id);

~CMsgQueue();

bool MsgGet();

bool MsgCreat();

bool MsgSnd(const void *msg, size_t nbytes, int flag);

bool MsgRcv(void *msg, size_t nbytes, long type, int flag);

int GetMsgQueueID();

bool Destroy();

private:

int m_MsgQueueID;//消息队列的ID

key_t m_MsgKey; //创建消息队列需要的关键字

};

#endif

CMsgQueue.cpp

/*************************************************************************

> File Name: CMsgQueue.cpp

> Author: KentZhang

> Mail: zhchk2010@qq.com

> Created Time: Wed 02 Sep 2015 08:20:14 PM CST

************************************************************************/

#include "CMsgQueue.h"

#ifndef RELEASE

#define DEBUG_ERROR(format,...) do{ printf(""format", FileName:%s, FuncName:%s, LineNum:%d\n",\

##__VA_ARGS__, __FILE__, __func__, __LINE__);}while(0)

#else

//当软件release时,这个宏应该把出错信息写入文件中,当然要考虑多线程的情况,此处代码省略

#defineDEBUG_ERROR(format,...) do{/*此处代码省略*/}while(0)

#endif

//构造函数中只是产生一个关键字

CMsgQueue::CMsgQueue(const char* path, int id)

{

m_MsgKey = ftok(path, id);

if (m_MsgKey < 0 )

{

DEBUG_ERROR("CMsgQueue() ftok(%s, %d) failed:%s", path, id, strerror(errno));

}

m_MsgQueueID = -1;

}

CMsgQueue::~CMsgQueue()

{

//在析构函数中,如果调用msgctl函数删除消息队列,

//那么有可能别的进程正在使用,因此谁创建,应该由

//谁调用Destory函数删除

}

//打开或者新建一个消息队列

bool CMsgQueue::MsgGet()

{

m_MsgQueueID = msgget(m_MsgKey, IPC_CREAT|0666);

if(-1 == m_MsgQueueID)

{

DEBUG_ERROR("CMsgQueue::MsgGet() failed:%s", strerror(errno));

return false;

}

return true;

}

//新创建消息队列

//有时候进程非正常退出时,消息队列没有删除,如果里面还有消息,

//将对程序的下一次运行产生影响,下面的函数可保证是新创建的消息队列

bool CMsgQueue::MsgCreat()

{

int nQueueID = msgget(m_MsgKey, IPC_CREAT|IPC_EXCL|0666);

if(-1 == nQueueID)

{

this->MsgGet();

msgctl(m_MsgQueueID, IPC_RMID, NULL);

m_MsgQueueID = 0;

return this->MsgGet();

}

m_MsgQueueID = nQueueID;

return true;

}

//发送消息

bool CMsgQueue::MsgSnd(const void *msg, size_t nbytes, int flag)

{

int nResult = msgsnd(m_MsgQueueID, msg, nbytes, flag);

if( -1 == nResult)

{

DEBUG_ERROR("CMsgQueue::msgSnd() failed:%s", strerror(errno));

return false;

}

return true;

}

//接收消息

bool CMsgQueue::MsgRcv(void *msg, size_t nbytes, long type, int flag)

{

int nResult = msgrcv(m_MsgQueueID,msg, nbytes, type, flag);

if( -1 == nResult)

{

DEBUG_ERROR("CMsgQueue::msgRcv() failed:%s", strerror(errno));

return false;

}

return true;

}

//获得消息队列ID

int CMsgQueue::GetMsgQueueID()

{

return m_MsgQueueID;

}

//删除消息队列

bool CMsgQueue::Destroy()

{

int nResult = msgctl(m_MsgQueueID, IPC_RMID, NULL);

if(-1 == nResult)

{

DEBUG_ERROR("CMsgQueue::Destroy() failed:%s", strerror(errno));

return false;

}

return true;

}

由于笔者的水平有限,出错在所难免,恳请读者拍砖指正,谢谢阅读。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值