C++封装Linux消息队列
2015-09-03 21:41
453 查看
消息队列是Linux进程间通信方式之一,在面向对象编程中,需要对其封装。
一、消息队列的特点
1、异步通信,消息队列会保存进程发送的消息,其他进程不一定要及时取走消息。
2、可以发送不同类型的消息,消息的头部用long类型的字段标记。
3、取消息时,不一定按先进先出的方式,可以按消息的类型来取。
4、消息队列内部是用一个链表来保存消息,当消息被取走后,这个消息就从链表中删除了,而且这个链表的长度
是有限制的,当消息存满后,不能再存入消息。
二、msgid和关键字
消息队列在内核中,要用一个非负整数来标记(类似于描述符或者句柄),这个非负整数称作msqid,即消息
队列的ID,但是要创建或者打开一个消息队列需要一个关键字,这个关键字其实是一个长整型数据。在进程
通信时,必须要约定使用同一个关键字,这样就可以得到同一个消息队列,因为消息队列是由内核维护的,
不同的进程使用相同关键字打开或者创建的消息队列,获得的msgid是相同的。
本例中使用一个文件路径加上课题ID(0~255)调用ftok函数产生一个关键字。
代码如下:
CMsgQueue.h
CMsgQueue.cpp
由于笔者的水平有限,出错在所难免,恳请读者拍砖指正,谢谢阅读。
一、消息队列的特点
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 <sys/types.h> #include <sys/msg.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> //封装消息队列 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时,这个宏应该把出错信息写入文件中,当然要考虑多线程的情况,此处代码省略 #define DEBUG_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; }
由于笔者的水平有限,出错在所难免,恳请读者拍砖指正,谢谢阅读。
相关文章推荐
- CentOS执行SU时 Authentication failure
- Linux多进程
- Linux-Hostname-details
- Linux-NTP-Server+Client
- linux运维实战练习-2015年8月30日课程作业
- centos6.5 下搭建lamp环境
- linux下运行C程序
- Linux export 命令
- linux命令进阶小记
- Linux rar乱码
- linux系统启动流程
- linux系统启动流程
- linux驱动篇之 driver_register 过程分析(一)
- centos7 安装zabbix-agent
- Linux系统mysql密码和远程访问设置
- linux下 mysql 操作
- Linux 系统挂载数据盘
- Linux设备驱动——字符驱动各种结构体
- Linux的O_DIRECT选项
- 从NFS启动Linux系统,OK6410