Linux IPC消息队列多进程通信编程封装

 

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!
......

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值