Posic IPC API使用--早年写的一部分代码
/********************************************************************
* Copyright* All rights reserved
*
* 文件名称: posix_ipcs.h
* 文件标示:
* 摘 要: posix IPC
* 线程安全: 是
*
* 当前版本: 1.0
* 作 者: shenyu
* 完成日期: 2010-9-8 10:12:09
*
* 备注
********************************************************************/
#ifndef _POSIX_IPCS_H_
#define _POSIX_IPCS_H_
#include "basic.h"
#include "datetime.h"
#include <mqueue.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#define MQ_BLOCK 0 //阻塞消息队列
#define MQ_NON_BLOCK 1 //非阻塞消息队列
#define LEN_POSIX_MSG_MAX 2048 //最大消息长度
//Posix 消息队列
class CPosixMQ
{
public:
CPosixMQ(const char * pszIpcName , int iDebugOn = DEBUG_OFF);
CPosixMQ(const char * pszIpcName , long lMaxMsgSize,long lMaxMsgCnt,int iDebugOn = DEBUG_OFF);
virtual ~CPosixMQ();
static long POSIX_MQ_OPEN_MAX(); //单个进程能打开的最大消息队列个数
static long POSIX_MQ_PRIO_MAX(); //任意消息队列最大优先级数
bool Exist(); //消息队列是否已经存在 存在则返回true 否则返回false
void SetIpcName(const char * pszIpcName); //设置消息队列关联的文件名
bool SetAttr(int iBlockFlag = MQ_BLOCK); //设置消息队列的属性 (只能设置组设和非阻塞属性 大小在创建的时候已经确定)
bool GetAttr(long * plMaxMsgCnt,long * plMaxMsgSize,long * plCurMsgs);//获取消息队列属性
bool SendMsg(char *pszMsgData, int iMsgLen,unsigned int uiPrio, int iTimeOut = INFINITE) const;//数据发送到消息队列
bool RecvMsg(char *pszMsgData, int *piMsgLen,unsigned int * puiPrio, int iTimeOut = INFINITE) const;//数据从消息队列读出
bool Open(int iCreateMSQ = CREATE_FORCE ); //打开或者创建不存在的队列
bool Close(); //关闭打开的消息队列
int Clear() ; //清空消息队列
bool Remove(); //删除消息队列
int MsgCnt() ; //当前消息个数
void SetDeBugOn(){m_iDebugOn = DEBUG_ON; }
protected:
private:
mqd_t m_mqd; //posix 消息队列标识
mq_attr m_attr; //消息队列属性
char m_szIpcName[LEN_FILE_NAME+1]; // 消息队列关联的名称
int m_iDebugOn; // 0 -表示不打开调试日志 1-表示打开调试日志
};
//Posix 共享内存
class CPosixShm
{
public:
CPosixShm(const char * pszIpcName ,int iDebugOn = DEBUG_OFF);
virtual~CPosixShm();
void * Alloc(int iSize); //申请共享内存
bool Attach(); //将进城与共享内存关联
void Detach(); //删除进程与共享内存的关联
bool Exist() ; //消息队列是否已经存在 存在则返回true 否则返回false
void SetIpcName(const char * pszIpcName); //设置共享内存关联的文件名
bool Open(int iCreateShm = CREATE_FORCE ); //打开或者创建共享内存
bool Close(); //关闭共享内存的关联
bool Remove(); //删除共享内存
int Size() ; //当前共享内存的大小
void *GetShmPoint() const {return m_pvShmHead;} //获取共享内存块指针
void SetDeBugOn(){m_iDebugOn = DEBUG_ON; }
protected:
private:
int m_iShmId; //共享内存
char m_szIpcName[LEN_FILE_NAME+1]; // 共享内存关联的名称
int m_iDebugOn; // 0 -表示不打开调试日志 1-表示打开调试日志
void *m_pvShmHead; //指向共享内存块的首指针
};
/********************************************************************
* Copyright
* All rights reserved
*
* 文件名称: posix_ipcs.h
* 文件标示:
* 摘 要: posix IPC
* 线程安全: 是
*
* 当前版本: 1.0
* 作 者: shenyu
* 完成日期: 2010-9-8 10:12:09
*
* 备注
消息队列默认 消息个数10 消息大小 8192
$ cat /proc/sys/fs/mqueue/msgsize_max
8192
$ cat /proc/sys/fs/mqueue/queues_max
256
$ cat /proc/sys/fs/mqueue/msg_max
10
/etc/sysctl.conf
#add by shenyu Posix Setting
fs.mqueue.msg_max=10000
fs.mqueue.msgsize_max=8192
消息队列的容量指 ulimit -q 819200
修改该值:ulimit -q 8192000(仅仅root能使用好像)
消息队列大小*消息长度+某个常量(系统) < 819200 (大概为600*1024)
********************************************************************/
#include "posix_ipcs.h"
/**********************************Posix 消息队列*****************************************************/
/*
功能:构造函数(用于打开已经存在的消息队列)
参数:无
返回值:无
*/
CPosixMQ::CPosixMQ(const char * pszIpcName ,int iDebugOn )
{
SetIpcName(pszIpcName);
m_mqd = (mqd_t)-1;
memset(&m_attr,0,sizeof(m_attr));
m_iDebugOn = iDebugOn;
}
/*
功能:构造函数(用于创建或者打开消息队列)
参数:
const char * pszIpcName[in] IPC名称
long lMaxMsgSize[in] 一个消息的最多字节数
long lMaxMsgCnt[in] 消息的最多个数
int iDebugOn[in] 调试
返回值:无
备注:
创建时只关注消息大小和消息的个数,而阻塞和非阻塞需要用mq_setattr来设置修改,它忽略其他参数
*/
CPosixMQ::CPosixMQ(const char * pszIpcName ,long lMaxMsgSize, long lMaxMsgCnt,int iDebugOn )
{
//IPC名称
SetIpcName(pszIpcName);
//消息队列属性 消息队列默认为阻塞模式
memset(&m_attr,0,sizeof(m_attr));
m_attr.mq_maxmsg = lMaxMsgCnt;
m_attr.mq_msgsize = lMaxMsgSize;
m_attr.mq_flags = 0;
m_mqd = (mqd_t)-1;
m_iDebugOn = iDebugOn;
}
/*
功能:析构函数
参数:无
返回值:无
*/
CPosixMQ::~CPosixMQ()
{
}
/*
功能:单个进程能打开的最大消息队列个数 -1可能表示无明确定义 (POSIX要求至少为8)
参数:无
返回值:
单个进程能打开的最大消息队列个数
*/
long CPosixMQ::POSIX_MQ_OPEN_MAX()
{
return sysconf(_SC_MQ_OPEN_MAX);
}
/*
功能:任意消息队列最大优先级数 -1可能表示无明确定义 (POSIX要求至少为32)
参数:无
返回值:
任意消息队列最大优先级数
*/
long CPosixMQ::POSIX_MQ_PRIO_MAX()
{
return sysconf(_SC_MQ_PRIO_MAX);
}
/*
功能:设置与消息队列关联的文件名(其他函数调用的前提)
参数:
char * pszIpcName[in] Posix 消息队列名称
返回值:
无
*/
void CPosixMQ::SetIpcName(const char * pszIpcName)
{
memset(m_szIpcName,0,sizeof(m_szIpcName));
snprintf(m_szIpcName,sizeof(m_szIpcName),"/%s.msq",pszIpcName);
}
/*
功能:设置消息队列的属性 (创建时只关注消息大小和消息的个数,而阻塞和非阻塞需要用mq_setattr来设置修改,它忽略其他参数)
参数:
int iBlockFlag [in] 阻塞或者非阻塞
返回值:
true 成功
false 设置失败
*/
bool CPosixMQ::SetAttr(int iBlockFlag /* = MQ_BLOCK */)
{
int iRet = -1;
//忽略其他参数
m_attr.mq_flags = (iBlockFlag == MQ_NON_BLOCK) ? O_NONBLOCK:0;
iRet = mq_setattr(m_mqd,&m_attr,NULL);
if (iRet != 0)
{
return false;
}
return true;
}
/*
功能:获取消息队列的属性 (创建时只关注消息大小和消息的个数,而阻塞和非阻塞需要用mq_setattr来设置修改,它忽略其他参数)
参数:
long * plMaxMsgCnt[out] 最多消息个数
long * plMaxMsgSize[out]最大单个消息大小
long * plCurMsgs[out] 当前消息个数
返回值:
bool 成功
false 失败
*/
bool CPosixMQ::GetAttr(long * plMaxMsgCnt,long * plMaxMsgSize,long * plCurMsgs)
{
int iRet = -1;
mq_attr attr;
if(m_mqd == (mqd_t)-1)
{
return false;
}
memset(&attr,0,sizeof(attr));
iRet = mq_getattr(m_mqd,&attr);
if (iRet != 0)
{
return false;
}
*plMaxMsgCnt = attr.mq_maxmsg;
*plMaxMsgSize = attr.mq_msgsize;
*plCurMsgs = attr.mq_curmsgs;
return true;
}
/*
功能:打开或者创建不存在的队列
参数:
int iCreateMSQ[in] 是否强制创建队列
返回值:
true 成功
false 失败
*/
bool CPosixMQ::Open(int iCreateMSQ )
{
int iRet = -1;
int iFlags;
if (m_szIpcName[0] == '\0')
{
return false;
}
if (iCreateMSQ == CREATE_FORCE)
{
iFlags = O_RDWR | O_CREAT;
}
else
{
iFlags = O_RDWR ;
}
//未设置属性
if (m_attr.mq_maxmsg == 0)
{
m_mqd = mq_open(m_szIpcName, iFlags,0666,NULL);
}
else
{
m_mqd = mq_open(m_szIpcName, iFlags,0666,&m_attr);
}
if (m_mqd == (mqd_t)-1)
{
if (m_iDebugOn == DEBUG_ON)
{
perror("mq_open:");
printf("(%s-%d) mq_open fail! [%s] ,iRet = [%d]\n",FILELINE,m_szIpcName,iRet);
}
return false;
}
if (m_iDebugOn == DEBUG_ON)
{
printf("(%s-%d) mq_open succ!\n",FILELINE);
}
return true;
}
/*
功能:关闭打开的消息队列
参数:无
返回值:
SUCC 成功删除
FAIL 删除失败
*/
bool CPosixMQ::Close()
{
return (mq_close(m_mqd) == (mqd_t)0);
}
/*
功能:消息队列是否已经存在 (需要先设置消息队列对应的文件名称)
参数:无
返回值:
存在则返回true
否则返回false
*/
bool CPosixMQ::Exist()
{
int iRet = -1;
if (!Open(CREATE_NO_FORCE))
{
return false;
}
Close();
return true;
}
/*
功能:清空消息队列里的消息
参数:无
返回值:
num 清除的消息个数
FAIL 处理失败
*/
int CPosixMQ::Clear()
{
int iRet = -1,iCnt = 0;
int iFlags;
char szMsgTmp[LEN_POSIX_MSG_MAX+1];
unsigned int uiPrio;
struct timespec timewake;
if ( m_mqd == (mqd_t)-1 || m_szIpcName[0] == '\0' )
{
return FAIL;
}
//清空消息队列
while (1)
{
CDateTimeH::AbsTimeFromNow(0,&timewake);
memset(szMsgTmp,0,sizeof(szMsgTmp));
iRet = mq_timedreceive(m_mqd, szMsgTmp,LEN_POSIX_MSG_MAX,&uiPrio,&timewake);
if(iRet < 0 )
{
break;
}
iCnt++;
}
return iCnt;
}
/*
功能:删除消息队列
参数:无
返回值:
SUCC 成功删除
FAIL 删除失败
*/
bool CPosixMQ::Remove()
{
return (mq_unlink(m_szIpcName) == (mqd_t)0);
}
/*
功能:当前消息个数
参数:无
返回值:
>=0 当前消息的个数
*/
int CPosixMQ::MsgCnt()
{
int iRet = -1;
struct mq_attr attr;
memset(&attr,0,sizeof(attr));
iRet = mq_getattr(m_mqd,&attr);
if (iRet != 0 )
{
return -1;
}
if (m_iDebugOn == DEBUG_ON)
{
printf("(%s-%d) mq_flags = %ld,max msgs = %ld ,max bytes one msg = %ld,current on queue = %ld\n",
FILELINE,attr.mq_flags, attr.mq_maxmsg,attr.mq_msgsize,attr.mq_curmsgs);
}
return attr.mq_curmsgs;
}
/*
功能:写入消息队列数据 (不能像system v消息队列一样 每次都打开 每次都打开 则文件描述符加1)
参数:
char *pszMsgData[in]写入的消息数据
int iMsgLen[in]消息数据长度
unsigned int uiPrio[in] 消息优先级 1-32
int iTimeOut[in]超时时间(单位ms)<0 阻塞等待,=0 非阻塞等待,>0超时控制
返回:
SUCC 成功
< 0 失败
*/
bool CPosixMQ::SendMsg(char *pszMsgData, int iMsgLen,unsigned int uiPrio, int iTimeOut /* = INFINITE */) const
{
int iRet = -1;
int iFlags;
if ( m_mqd == (mqd_t)-1 || m_szIpcName[0] == '\0' )
{
return false;
}
//发送数据 无超时设置 则阻塞发送
if (iTimeOut == INFINITE)
{
iRet = mq_send(m_mqd, pszMsgData,iMsgLen,uiPrio);
if(iRet != 0 )
{
if (m_iDebugOn == DEBUG_ON)
{
perror("mq_send:");
printf("(%s-%d) mq_send [%d] Faild!errno = [%d]\n",FILELINE,m_mqd,errno);
}
return false;
}
}
else
{
struct timespec timewake;
CDateTimeH::AbsTimeFromNow(iTimeOut,&timewake);
iRet = mq_timedsend(m_mqd, pszMsgData,iMsgLen,uiPrio,&timewake);
if(iRet != 0 )
{
if (m_iDebugOn == DEBUG_ON)
{
perror("mq_send:");
printf("(%s-%d) mq_timedsend [%d] Faild!errno = [%d]\n",FILELINE,m_mqd,errno);
}
return false;
}
}
return true;
}
/*
功能: 读取消息队列数据 (不能像system v消息队列一样 每次都打开 每次都打开 则文件描述符加1)
参数:
char *pszMsgData[out]写入的消息数据
int iMsgLen[out]消息数据长度
unsigned int * puiPrio[out]消息优先级
int iTimeOut[in]超时时间(秒)<0 阻塞等待,=0 非阻塞等待,>0超时控制
返回:
SUCC 成功
< 0 失败
*/
bool CPosixMQ::RecvMsg(char *pszMsgData, int *piMsgLen,unsigned int * puiPrio, int iTimeOut /* = INFINITE */) const
{
int iRet = -1;
int iFlags;
if ( m_mqd == (mqd_t)-1 || m_szIpcName[0] == '\0' )
{
return false;
}
//发送数据 无超时设置 则阻塞接受
if (iTimeOut == INFINITE)
{
iRet = mq_receive(m_mqd, pszMsgData,LEN_POSIX_MSG_MAX,puiPrio);
if(iRet < 0 )
{
if (m_iDebugOn == DEBUG_ON)
{
perror("mq_send:");
printf("(%s-%d) mq_send [%d] Faild!errno = [%d]\n",FILELINE,m_mqd,errno);
}
return false;
}
}
else
{
struct timespec timewake;
CDateTimeH::AbsTimeFromNow(iTimeOut,&timewake);
iRet = mq_timedreceive(m_mqd, pszMsgData,LEN_POSIX_MSG_MAX,puiPrio,&timewake);
if(iRet < 0 )
{
if (m_iDebugOn == DEBUG_ON)
{
perror("mq_send:");
printf("(%s-%d) mq_timedsend [%d] Faild!errno = [%d]\n",FILELINE,m_mqd,errno);
}
return false;
}
}
*piMsgLen = iRet;
return true;
}
/**********************************Posix 消息队列*****************************************************/
/**********************************Posix 共享内存*****************************************************/
/*
功能:构造函数
参数:无
返回值:无
*/
CPosixShm::CPosixShm(const char * pszIpcName , int iDebugOn )
{
SetIpcName(pszIpcName);
m_iShmId = -1;
m_pvShmHead = NULL;
m_iDebugOn = iDebugOn;
}
/*
功能:析构函数
参数:无
返回值:无
*/
CPosixShm::~CPosixShm()
{
m_iShmId = -1;
memset(m_szIpcName,0,sizeof(m_szIpcName));
m_pvShmHead = NULL;
}
/*
功能:设置与共享内存关联的文件名(其他函数调用的前提)
参数:
char * pszIpcName[in] Posix 共享内存名称
返回值:
无
*/
void CPosixShm::SetIpcName(const char * pszIpcName)
{
memset(m_szIpcName,0,sizeof(m_szIpcName));
snprintf(m_szIpcName,sizeof(m_szIpcName),"/%s.shm",pszIpcName);
}
/*
功能:共享内存是否已经存在 (需要先设置共享内存对应的文件名称)
参数:无
返回值:
存在则返回true
否则返回false
*/
bool CPosixShm::Exist()
{
if (!Open(CREATE_NO_FORCE))
{
return false;
}
Close();
return true;
}
/*
功能:打开或者创建不存在的共享内存
参数:
int iCreateShm[in] 是否强制创建共享内存
返回值:
SUCC 成功删除
FAIL 删除失败
*/
bool CPosixShm::Open(int iCreateShm )
{
int iRet = -1;
int iFlags;
if (m_szIpcName[0] == '\0')
{
return false;
}
if (iCreateShm == CREATE_FORCE)
{
iFlags = O_RDWR | O_CREAT;
}
else
{
iFlags = O_RDWR ;
}
iRet = shm_open(m_szIpcName,iFlags,0666);
if (iRet < 0 )
{
if (m_iDebugOn == DEBUG_ON)
{
perror("shm_open:");
printf("(%s-%d) shm_open [%d] Faild!errno = [%d]\n",FILELINE,iRet,errno);
}
return false;
}
m_iShmId = iRet;
return true;
}
/*
功能:关闭打开的共享内存
参数:无
返回值:
SUCC 成功删除
FAIL 删除失败
*/
bool CPosixShm::Close()
{
return (close(m_iShmId) == 0);
}
/*
功能:当前共享内存的大小
参数:无
返回值:
>=0 当前共享内存的大小
<0 获取共享内存大小失败
*/
int CPosixShm::Size()
{
int iRet = -1;
struct stat shmstate;
if (!Open(CREATE_NO_FORCE))
{
return -1;
}
iRet = fstat(m_iShmId,&shmstate);
if (iRet != 0)
{
Close();
return -1;
}
Close();
return shmstate.st_size;
}
/*
功能:删除共享内存
参数:无
返回值:
SUCC 成功删除
FAIL 删除失败
*/
bool CPosixShm::Remove()
{
return (shm_unlink(m_szIpcName) == 0);
}
/*
功能:分配共享内存块(不存在则创建)
参数:
int iSize[in] 共享内存块大小 =0的时候表示共享内存已经创建
返回值:
NULL 申请内存失败
非NULL 指向共享内存的指针
*/
void* CPosixShm::Alloc(int iSize)
{
int iRet = -1;
int iCurSize = 0;
//共享内存不存在 则创建
if (!Exist())
{
if (m_iDebugOn == DEBUG_ON)
{
printf("(%s-%d) shm have not been created!\n",FILELINE);
}
if (!Open())
{
return NULL;
}
ftruncate(m_iShmId,iSize);
m_pvShmHead = mmap(NULL,iSize,PROT_READ|PROT_WRITE,MAP_SHARED,m_iShmId,0);
Close();
}
//如果已经存在 则判断大小 不够大则重新创建 够大则RESET内存
else
{
if (m_iDebugOn == DEBUG_ON)
{
printf("(%s-%d) shm have been created!\n",FILELINE);
}
iCurSize = Size();
//空间不足则将空间改为当前设置的大小
if (iCurSize < iSize)
{
if (!Open())
{
return false;
}
ftruncate(m_iShmId,iSize);
m_pvShmHead = mmap(NULL,iSize,PROT_READ|PROT_WRITE,MAP_SHARED,m_iShmId,0);
Close();
}
else //直接关联共享内存
{
if (!Attach())
{
return NULL;
}
}
}
return m_pvShmHead;
}
/*
功能:关联进程与共享内存块
参数:
返回值:
SUCC 成功
其他失败
*/
bool CPosixShm::Attach()
{
int iRet = -1;
int iSize = -1;
iSize = Size();
if (iSize < 0 )
{
return false;
}
if (!Open())
{
return false;
}
m_pvShmHead = mmap(NULL,iSize,PROT_READ|PROT_WRITE,MAP_SHARED,m_iShmId,0);
Close();
return true;
}
/*
功能:去掉关联进程与共享内存块
参数:
返回值:
SUCC 成功
其他失败
*/
void CPosixShm::Detach()
{
m_pvShmHead = NULL;
}
/**********************************Posix 共享内存*****************************************************/
#endif