1. MsgQue.h
#ifndef MSG_QUE_H
#define MSG_QUE_H
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include "Typedef.h"
#include "./Print.h"
#define MSG_QUE_SERVER 0 //消息队列作为服务端
#define MSG_QUE_CLIENT 1 //消息队列作为客户端
#define MSG_QUE_LEN 2048 //消息队列数据长度
//消息队列缓冲区
typedef struct{
int iKey; //发送或接收的微应用key值,例如A发往B,这里的key值表示B的键值
char buf[MSG_QUE_LEN]; //消息缓冲区
int iLen; //消息的有效长度
}TMsgBuf;
//IPC消息队列
typedef struct {
long iMsgtype; //消息类型
TMsgBuf tMsgBuf; //消息数据
}TMsgQue;
class CMsgQue{
public:
//描述:IPC消息队列构造函数
//参数:@key IPC键值,4字节16进制表示
// @fDebugInfo 用于调试信息输出
CMsgQue(key_t key, bool fDebugInfo=true);
//描述:析构函数
~CMsgQue();
private:
CPrint *m_pCPrint;
key_t m_key;
int m_iMsgId;
//描述:创建消息队列
//参数:无
//返回:小于0失败,反之成功
int MsgQueCreate();
//描述:销毁消息队列
//参数:无
//返回:小于0失败,反之成功
int MsgQueDestory();
public:
//描述:消息发送
//参数:@pTMsgBuf 发送消息结构体
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为发送的字节数
int MsgSend(const TMsgBuf *pTMsgBuf, int iBlockMode=IPC_NOWAIT);
//描述:消息接收
//参数:@pTMsgBuf 接收消息结构体
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为接送的字节数
int MsgRecv(TMsgBuf *pTMsgBuf, int iBlockMode=IPC_NOWAIT);
};
//描述:消息队列初始化
void MsgQueInit(void);
//描述:消息队列释放
void MsgQueFree(void);
//描述:消息队列请求
//参数:@iKey 消息队列键值
//返回:成功返回iKey所属消息队列对象,否则为NULL
CMsgQue * MsgQueReq(int iKey);
//描述:消息队列发送
//参数:@pCMQ 发送的消息队列对象
// @pMsgBuf 发送的消息队里数据
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为发送的字节数
int MsgQueSend(CMsgQue *pCMQ, const TMsgBuf *pMsgBuf, int iBlock=IPC_NOWAIT);
//描述:消息队列接收
//参数:@pCMQ 接收的消息队列对象
// @pMsgBuf 接收的消息队里数据
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为接送的字节数
int MsgQueRecv(CMsgQue *pCMQ, TMsgBuf *pMsgBuf, int iBlock=IPC_NOWAIT);
#endif //MSG_QUE_H
2. MsgQue.cpp
#include "MsgQue.h"
#include <unistd.h>
#include <execinfo.h>
#include <signal.h>
//微应用app所属键值,每个app都需要一个唯一的键值,不能冲突!
//键值添加使用规则:
//1.宏定义增加
//2.将宏定义的键值添加到g_key[]数组中
//微应用内部使用规则
:
//1. MsgQueInit()
//2. MsgQueReq(key) //由上面宏定义填充的键值
//3. MsgQueRecv()
//4. MsgQueSend()
//5. MsgQueFree()
#define IPC_KEY_APP0 1
#define IPC_KEY_APP1 2
#define IPC_KEY_APP2 3
static int g_key[] = {IPC_KEY_APP0, IPC_KEY_APP1, IPC_KEY_APP2};
static int g_keyNum = sizeof(g_key)/sizeof(g_key[0]);
//描述:IPC消息队列构造函数
//参数:@key IPC键值,4字节16进制表示
// @fDebugInfo 用于调试信息输出
CMsgQue::CMsgQue(key_t key, bool fDebugInfo)
{
m_key = key;
m_pCPrint = new CPrint();
MsgQueCreate();
}
//描述:析构函数
CMsgQue::~CMsgQue()
{
MsgQueDestory();
delete m_pCPrint;
}
//描述:创建消息队列
//参数:无
//返回:小于0失败,反之成功
int CMsgQue::MsgQueCreate()
{
if ((m_iMsgId=msgget(m_key, IPC_CREAT)) < 0)
{
if ((m_iMsgId=msgget(m_key, IPC_CREAT|IPC_EXCL|0666)) < 0)
m_pCPrint->PrintStr("CMsgQue::MsgQueCreate:msgget: %s\n", strerror(m_iMsgId));
}
if (m_iMsgId > 0)
m_pCPrint->PrintStr("CMsgQue::MsgQueCreate:msgget: key=0x%08x, iMsgId=0x%08x\n", m_key, m_iMsgId);
return m_iMsgId;
}
//描述:销毁消息队列
//参数:无
//返回:小于0失败,反之成功
int CMsgQue::MsgQueDestory()
{
int iRet;
if((iRet=msgctl(m_iMsgId, IPC_RMID, NULL)) < 0)
{
perror("CMsgQue::DestoryMsgQue:msgctl");
return -1;
}
return iRet;
}
//描述:消息发送
//参数:@pTMsgBuf 发送消息结构体
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为发送的字节数
int CMsgQue::MsgSend(const TMsgBuf *pTMsgBuf, int iBlockMode)
{
TMsgQue tMsgQue;
if ((pTMsgBuf->iLen+4) > MSG_QUE_LEN)
{
m_pCPrint->PrintStr("IpcMsgQue::MsgSend: MSG_QUE_LEN=%d < iLen=%d over len!!!\n", MSG_QUE_LEN, pTMsgBuf->iLen+4);
return -1;
}
memset((BYTE*)&tMsgQue, 0, sizeof(tMsgQue));
tMsgQue.tMsgBuf = *pTMsgBuf;
tMsgQue.iMsgtype = 0x01;
return msgsnd(m_iMsgId, (void*)&tMsgQue, sizeof(tMsgQue.tMsgBuf), iBlockMode); //非阻塞模式
}
//描述:消息接收
//参数:@pikey 接收到消息的key值
// @pbBuf 待接收的缓冲区
// @iLen pbBuf最大接收缓冲区长度
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为接送的字节数
int CMsgQue::MsgRecv(TMsgBuf *pTMsgBuf, int iBlockMode)
{
TMsgQue tMsgQue;
int iRet;
memset((BYTE*)&tMsgQue, 0, sizeof(tMsgQue));
if((iRet=msgrcv(m_iMsgId, (void*)&tMsgQue, sizeof(tMsgQue.tMsgBuf), 0, iBlockMode)) < 0) //非阻塞模式
return iRet;
*pTMsgBuf = tMsgQue.tMsgBuf;
return pTMsgBuf->iLen;
}
static CMsgQue **g_ppCMsgQue;
//描述:消息队列初始化
void MsgQueInit(void)
{
int iKeyidx;
g_ppCMsgQue = new CMsgQue * [g_keyNum];
if (g_ppCMsgQue != NULL)
{
for (iKeyidx=0; iKeyidx<g_keyNum; iKeyidx++)
g_ppCMsgQue[iKeyidx] = new CMsgQue(g_key[iKeyidx]);
}
}
//描述:消息队列释放
void MsgQueFree(void)
{
int iKeyidx;
for (iKeyidx=0; iKeyidx<g_keyNum; iKeyidx++)
delete[] g_ppCMsgQue[iKeyidx];
delete[] g_ppCMsgQue;
}
//描述:消息队列请求
//参数:@iKey 消息队列键值
//返回:成功返回iKey所属消息队列对象,否则为NULL
CMsgQue * MsgQueReq(int iKey)
{
int iKeyidx;
for (iKeyidx=0; iKeyidx<g_keyNum; iKeyidx++)
{
if (g_key[iKeyidx] == iKey)
{
//printf("GetMsgQue: iKey=%d\n", iKey);
return g_ppCMsgQue[iKeyidx];
}
}
return NULL;
}
//描述:消息队列发送
//参数:@pCMQ 发送的消息队列对象
// @pMsgBuf 发送的消息队里数据
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为发送的字节数
int MsgQueSend(CMsgQue *pCMQ, const TMsgBuf *pMsgBuf, int iBlock)
{
return pCMQ->MsgSend(pMsgBuf, iBlock);
}
//描述:消息队列接收
//参数:@pCMQ 接收的消息队列对象
// @pMsgBuf 接收的消息队里数据
// @iBlockMode 阻塞模式,IPC_NOWAIT--非阻塞,0--阻塞
//返回:小于0失败,反之为接送的字节数
int MsgQueRecv(CMsgQue *pCMQ, TMsgBuf *pMsgBuf, int iBlock)
{
return pCMQ->MsgRecv(pMsgBuf, iBlock);
}
3. main.cpp
#include "MsgQue.h"
#include <unistd.h>
#include <execinfo.h>
#include <signal.h>
int main(int argc, char *argv[])
{
CMsgQue *pCMQ_Ser, *pCMQ_Cli;
char bBuf[1024];
int iKey, iKeyRecv, iRet;
char c;
TMsgBuf tMsgBuf;
if (argc != 2)
{
printf("argc=2, current argc=%d.\n", argc);
printf("Example: ./MsgQue X, X is 0, 1, 2,...\n");
exit(0);
}
else
{
printf("iKey = 0x%08x\n", iKey=atoi(argv[1]));
//1. 注册所有微应用key值
MsgQueInit();
//2. 获取当前微应用的key值消息队列对象
if ((pCMQ_Ser=MsgQueReq(iKey)) != NULL)
{
printf("Press 's' send, 'r' receive!\n");
c = getchar();
printf("Recv char=%c.\n", c);
//while (1)
{
if (c == 'r')
{
while (1)
{
memset((BYTE*)&tMsgBuf, 0, sizeof(tMsgBuf));
if (MsgQueRecv(pCMQ_Ser, &tMsgBuf, 0) > 0)
{
printf("Current key=%d: Recv from key=%d,buf=%s\n", iKey, tMsgBuf.iKey, tMsgBuf.buf);
if ((pCMQ_Cli=MsgQueReq(tMsgBuf.iKey)) != NULL)
{
iKeyRecv = tMsgBuf.iKey;
memset((BYTE*)&tMsgBuf, 0, sizeof(tMsgBuf));
tMsgBuf.iKey = iKey;
strcpy(tMsgBuf.buf, "hello world!");
tMsgBuf.iLen = strlen(tMsgBuf.buf);
printf("Current key=%d: send to key=%d, buf=%s\n", iKey, iKeyRecv, tMsgBuf.buf);
if (((iRet=MsgQueSend(pCMQ_Cli, &tMsgBuf, 0))) < 0)
printf("Current key=%d: send to key=%d, error=%s\n", iKey, tMsgBuf.iKey, strerror(iRet));
}
}
}
}
else if (c == 's')
{
memset((BYTE*)&tMsgBuf, 0, sizeof(tMsgBuf));
tMsgBuf.iKey = 0x02; //默认要发往的key对象
strcpy(tMsgBuf.buf, "hello world!");
tMsgBuf.iLen = strlen(tMsgBuf.buf);
if ((pCMQ_Cli=MsgQueReq(0x01)) != NULL) //获取接收到的消息所属key值对象
{
printf("Current key=%d: send to key=%d, buf=%s\n", iKey, tMsgBuf.iKey, tMsgBuf.buf);
if (((iRet=MsgQueSend(pCMQ_Cli, &tMsgBuf, 0))) < 0)
printf("Current key=%d: send to key=%d, error=%s\n", iKey, tMsgBuf.iKey, strerror(iRet));
}
while (1)
{
memset((BYTE*)&tMsgBuf, 0, sizeof(tMsgBuf));
if (MsgQueRecv(pCMQ_Ser, &tMsgBuf, 0) > 0)
{
printf("Current key=%d: Recv from key=%d,buf=%s\n", iKey, tMsgBuf.iKey, tMsgBuf.buf);
if ((pCMQ_Cli=MsgQueReq(tMsgBuf.iKey)) != NULL)
{
iKeyRecv = tMsgBuf.iKey;
memset((BYTE*)&tMsgBuf, 0, sizeof(tMsgBuf));
tMsgBuf.iKey = iKey;
strcpy(tMsgBuf.buf, "hello world!");
tMsgBuf.iLen = strlen(tMsgBuf.buf);
printf("Current key=%d: send to key=%d, buf=%s\n", iKey, iKeyRecv, tMsgBuf.buf);
if (((iRet=MsgQueSend(pCMQ_Cli, &tMsgBuf, 0))) < 0)
printf("Current key=%d: send to key=%d, error=%s\n", iKey, tMsgBuf.iKey, strerror(iRet));
}
}
}
}
}
}
MsgQueFree();
}
}
4. makefile
arm-linux-gnueabi-g++ MsgQue.cpp -o MsgQueApp
5. 测试(以下a b相互通信,通信流程为:A-->B, B-->A)
a. 控制台1,输入字符‘s’发送
root@NXBB:/mnt/nand/# ./MsgQueApp 2
iKey = 0x00000002
CMsgQue::MsgQueCreate:msgget: key=0x00000001, iMsgId=0x00020000
CMsgQue::MsgQueCreate:msgget: key=0x00000002, iMsgId=0x00028001
CMsgQue::MsgQueCreate:msgget: key=0x00000003, iMsgId=0x00030002
Press 's' send, 'r' receive!
......
Current key=2: send to key=1, buf=hello world!
Current key=2: Recv from key=1,buf=hello world!
Current key=2: send to key=1, buf=hello world!
Current key=2: Recv from key=1,buf=hello world!
Current key=2: send to key=1, buf=hello world!
Current key=2: Recv from key=1,buf=hello world!
Current key=2: send to key=1, buf=hello world!
Current key=2: Recv from key=1,buf=hello world!
Current key=2: send to key=1, buf=hello world!
Current key=2: Recv from key=1,buf=hello world!
Current key=2: send to key=1, buf=hello world!
......
b. 控制台2,输入字符‘r’接收
root@NXBB:/mnt/nand/# ./MsgQueApp 1
iKey = 0x00000001
CMsgQue::MsgQueCreate:msgget: key=0x00000001, iMsgId=0x00020000
CMsgQue::MsgQueCreate:msgget: key=0x00000002, iMsgId=0x00028001
CMsgQue::MsgQueCreate:msgget: key=0x00000003, iMsgId=0x00030002
Press 's' send, 'r' receive!
......
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
Current key=1: Recv from key=2,buf=hello world!
Current key=1: send to key=2, buf=hello world!
......