一个简单的消息队列类(封装system V消息队列)

基本的思想是,

1、将消息队列封装成一个类,可以简单地控制消息队列的建立、收发和删除。

2、更改消息协议时,不需要修改收发的类。

以下是代码,使用模板来达到上述第二点的要求,只要按规则定义了消息结构,则可以复用此消息队列的代码。因为使用了模板,所以使用了hpp头文件,将类和其成员函数都定义在hpp文件里,使用时只需要包含此头文件就可以了。


//DMMsgQueue.hpp
#ifndef _DMMSGQUEUE_HPP_
#define _DMMSGQUEUE_HPP_
#include <stdio.h>
#include <sys/msg.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
#ifdef __LINUX__
const int SVMSG_MODE = 0660;
#else
#include <sys/ipc.h>
const int SVMSG_MODE = MSG_R | MSG_W;
#endif
const int FIND_OR_CREATE = SVMSG_MODE | IPC_CREAT;
const int CREATE = SVMSG_MODE | IPC_CREAT | IPC_EXCL;

/**
 * @brief Structure of message sample, every structure of message must contain
 * the member mtype and member funtion MsgSize just like this sample struct and
 * you can add more members to fit your need
 */
struct DMBaseMsg
{
  long mtype;
  size_t MsgSize() const
  {
    return 0;
  }
};

/**
 * @brief Message queue base on system V message queue 
 */
template <typename T>
class DMMsgQueue
{
 public:
  DMMsgQueue(std::string strQueueName, int flag = FIND_OR_CREATE);
  ~DMMsgQueue(){};
  bool Recv(T& msgObject, int flag = 0);
  bool Send(const T& msgObject, int flag = 0);
  bool RecvTimeOut(T& msgObject, int nTimeout = 5);
  bool SendTimeOut(const T& msgObject, int nTimeout = 5);
  bool Remove();
 private:
  int m_Msqid;
};

template <typename T>
DMMsgQueue<T>::DMMsgQueue(std::string strQueueName, int flag)
{
  std::string strFile= "/tmp/";
  strFile += strQueueName;
  std::string strCmd = "touch ";
  strCmd += strFile;
  system(strCmd.c_str());
  key_t mqkey = ftok(strFile.c_str(), 42);
  if(mqkey == -1)
  {
    throw TCException("DMMsgQueue create error!Ftok error!");
  }
  m_Msqid = msgget(mqkey, flag);
  if(errno = EEXIST && flag == CREATE)
  {
    throw TCException("DMMsgQueue create error!MsgQueue Existed!");
  }

  if(m_Msqid == -1)
  {
    PRINTTRACE(g_szError, "[DMMsgQueue::DMMsgQueue]Error! errno:%d\n", errno);
    throw TCException("DMMsgQueue create error!");
  }
}

template <typename T>
bool DMMsgQueue<T>::Send(const T& msgObject, int flag)
{
  if(0 == msgsnd(m_Msqid, (void*)&msgObject, msgObject.MsgSize(),flag))
  {
    return true;
  }
  else
  {
    return false;
  }
}

template <typename T>
bool DMMsgQueue<T>::Recv(T& msgObject, int flag)
{
  if(0 < msgrcv(m_Msqid, (void*)&msgObject, msgObject.MsgSize(),msgObject.mtype, flag))
  {
    return true;
  }
  else
  {
    return false;
  }
}

template <typename T>
bool DMMsgQueue<T>::RecvTimeOut(T& msgObject, int nTimeout)
{
  time_t starttime = time(NULL);
  while(true)
  {
    int nReturn = 0;
    nReturn = msgrcv(m_Msqid, (void*)&msgObject, msgObject.MsgSize(), msgObject.mtype, IPC_NOWAIT);
    if(0 < nReturn)
    {
      return true;
    }
    else
    {
      if(errno == ENOMSG || 0 == nReturn)
      {
        if(time(NULL) - starttime < nTimeout)
        {
          usleep(50);
          continue;
        }
      }

      return false;
    }
  }
}

template <typename T>
bool DMMsgQueue<T>::SendTimeOut(const T& msgObject, int nTimeout)
{
  time_t starttime = time(NULL);
  while(true)
  {
    int nReturn = 0;
    nReturn = msgsnd(m_Msqid, (void*)&msgObject, msgObject.MsgSize(), IPC_NOWAIT);
    if(0 == nReturn)
    {
      return true;
    }
    else
    {
      if(errno == EAGAIN)
      {
        if(time(NULL) - starttime < nTimeout)
        {
          usleep(50);
          continue;
        }
      }

      return false;
    }
  }
}

/**
 * @brief If you want to remove a message queue you have created , try this
 *
 * @return 
 */
template <typename T>
bool DMMsgQueue<T>::Remove()
{
  if(!msgctl(m_Msqid, IPC_RMID, NULL))
  {
    return false;
  }

  return true;
}
#endif

这里需要注意一点,编译时必须定义宏__LINUX__,这里主要出于我工作时移植性的考虑,某些宏在AIX上有定义,而linux中没有。另外,构造函数中所使用的ftok函数的注意事项,可以参照我之前写的另一个文章。

以下再举一个测试函数例子:

#include "DMMsgQueue.hpp"

int main(int argc, char **argv)
{
  DMBaseMsg msg;
  msg.mtype = 100;
  memset(msg.mmsg, 0x00, 1024);
  sprintf(msg.mmsg, "abc");
  DMMsgQueue<DMBaseMsg> my_mq("my_mq");
  std::cout << "Sending..." << std::endl;
  if(!my_mq.Send(msg))
  {
    std::cout << "send error .." << std::endl;
    my_mq.Remove();
    return -1;
  }
  DMBaseMsg msg2;
  msg2.mtype = 200;
  std::cout << "Receiving..." << std::endl;
  if(!my_mq.RecvTimeOut(msg2, 10))
  {
    std::cout << "Receive error" << std::endl;
    my_mq.Remove();
    return -1;
  }
  std::cout << msg2.mmsg<< std::endl;

  my_mq.Remove();
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值