#include <winsock2.h>
namespace TCPCONNECT
{
enum BLOCKING_MODE
{
MODE_BLOCKING = 0,
MODE_UNBLOCKING = 1
};
enum COMMUNICATION_MODE
{
MODE_SERVER = 1,
MODE_CLIENT = 2
};
enum EVENT_TYPE
{
// Client
CONNECTINT__EVENT = 0, // 正在连接
CONNECT_SUCCESS_EVENT = 1, // 连接成功
CONNECT_FAILD_EVENT = 2, // 连接失败
// Server
LISTEN_SUCCESS_EVENT = 5, // 侦听成功
LISTEN_FAILD_EVENT = 6, // 侦听失败
CONNECT_GET_IN_EVENT = 7, // 连接接入
CONNECT_QUIT_EVENT = 8, // 连接退出
// SHARE
CONNECT_BREAKED_EVENT = 12, // 断开连接
RECEIVE_TIMEOUT_EVENT = 13, // 数据接收超时
HAS_DIRTY_DATA_CLEAR = 51, // 连接上存在脏数据时,清除掉脏数据
HAS_DIRTY_DATA_BREAK = 52 // 连接上存在脏数据时,SOCKET断开
};
typedef struct tagConnectInfo
{
tagConnectInfo()
{
memset(this, 0x00, sizeof(tagConnectInfo));
}
int iSocketHandle;
char szConnectIP[30]; // 远端IP
unsigned short siConnectPort; // 远端PORT
char szLocalIp[30]; // 本地IP
unsigned short siLocalPort; // 本地PORT
}CONNECT_INFO;
typedef struct tagClientDetailInfo
{
tagClientDetailInfo()
{
// modified by liusg 20170105 支持不确认长度的大数据接收
memset(this, 0x00, sizeof(CONNECT_INFO));
pclTcpConnect = NULL;
pszRecvBuf = NULL;
iRecvBufferSize = 0;
iRcvSum = 0;
strRecvBuf.clear();
// modified end
}
CONNECT_INFO stConnectInfo; // 连接信息
void* pclTcpConnect; // 连接对象
char* pszRecvBuf; // 接收缓冲区
int iRecvBufferSize; // 接收缓冲区大小
int iRcvSum; // 总接收数据长度
std::string strRecvBuf; // 对应连接大数据接收缓存区 // add by liusg 20170105 支持不确认长度的大数据接收
}CLIENT_DETAIL_INFO;
}
#pragma once
class CCommuAnalyzer
{
public:
CCommuAnalyzer(void);
virtual ~CCommuAnalyzer(void);
/*
* Desc:
* 依据输入的业务报文,打包成网络报文并输出
* 默认的通讯分析器只含简单的网络层组包解包逻辑逻辑,不包含对于业务协议的包。网络包规则如下:
* 网络包头包括:包头识别码(换行回车符:'\n\r')+ 一个整型值的长度,无包尾
* 注:当符合以下条件的情况下可以不调用该接口
* 1、业务报文件长度小于 TCPConnect中定义的:最大网络接收缓冲区大小
* 2、对网络包组包规则无特殊要求
* Pram:
* pszBodyIn 业务报文
* iBodyLenIn 业务报文长度
* pszNetBufOut 网络报文 【输出参数由调用者清除】
* iBufLenOut 网络报文长度
* Retr:
* bool 打包成功返回 true, 打包失败返回 false
*/
virtual bool PackNetPackage(char* pszBodyIn, int iBodyLenIn, char*& pszNetBufOut, int& iBufLenOut);
/*
* Desc:
* 依据输入的网络接收缓冲区,判断是否存在脏数据需要被清理,并通过返回值iSkipLen告知需要被处理的脏数据长度。
* 必须实现存在错误包时的应对处理,由(-1:抛弃错误数据,但不断开网络;-2:中断网络)
*
* Pram:
* pszNetRcvBufIn 网络接收缓冲区
* iNetRcvBufLenIn 网络接收缓冲区长度
* iSkipLen 网络接收缓冲区超始位置开始需要被忽略的脏数据长度, 必须正确,否则会导致清楚正确的数据
* Retr:
* int 0:无脏数据 -1:有脏数据但不中断网络, -2:有脏数据需要中断网络
*/
virtual int IsExistDirtyData(char* pszNetRcvBufIn, int iNetRcvBufLenIn, int& iSkipLen);
/*
* Desc:
* 依据输入的网络接收缓冲区,判断是否存在完整的网络包
*
* Pram:
* pszNetRcvBufIn 网络接收缓冲区
* iNetRcvBufLenIn 网络接收缓冲区长度
* Retr:
* bool true:有完整网络报文; false:无完整网络报文
*/
virtual bool IsHasFullPackage(char* pszNetRcvBufIn, int iNetRcvBufLenIn);
/*
* Desc:
* 依据输入的网络接收缓冲区,解包出第一个完整业务报文输出
* 在调用该函数之前,必须先调用 IsHasFullPackage(...),且返回值必须为0
* Pram:
* pszNetRcvBufIn 网络接收缓冲区
* iNetRcvBufLenIn 网络接收缓冲区长度
* pszBodyOut 完整的业务报文 【输出参数,由应用(CommuApplication)负责删除】
* iBodyLenOut 业务报文长度(即网络报文体)
* iHeadLenOut 网络报文头长度
* iTailLenOut 网络报文尾长度
* Retr:
* bool 解包成功返回 true, 解包失败返回 false
*/
virtual bool UnpackNetPackage(char* pszNetRcvBufIn, int iNetRcvBufLenIn, char*& pszBodyOut, int& iBodyLenOut, int& iHeadLenOut, int& iTailLenOut);
protected:
int m_iNetPackHeadLen; // 网络包头长度
int m_iNetPackTailLen; // 网络包体长度
};
#include "StdAfx.h"
#include "CommuAnalyzer.h"
#include <iostream>
#include <WinSock2.h>
CCommuAnalyzer::CCommuAnalyzer(void)
:m_iNetPackHeadLen(6)
,m_iNetPackTailLen(0)
{
}
CCommuAnalyzer::~CCommuAnalyzer(void)
{
}
bool CCommuAnalyzer::PackNetPackage(char* pszBodyIn, int iBodyLenIn, char*& pszNetBufOut, int& iBufLenOut)
{
bool bReturn = false;
int iHeadLen = 6;
int iTailLen = 0;
// if (pszBodyIn == NULL) {
// std::cout<< "业务报文入参无效" << std::endl;
// }
// else
{
iBufLenOut = iHeadLen + iBodyLenIn + iTailLen;
pszNetBufOut = new char[iBufLenOut];
memset(pszNetBufOut, 0x00, iBufLenOut);
if (pszNetBufOut == NULL)
{
std::cout<< "分配内存存储打包后的网络报文失败" << std::endl;
}
else
{
// 报头
pszNetBufOut[0] = '\n';
pszNetBufOut[1] = '\r';
memcpy(pszNetBufOut + 2, &iBodyLenIn, sizeof(int));
// 报体
memcpy(pszNetBufOut + iHeadLen, pszBodyIn, iBodyLenIn);
// 无包尾
}
bReturn = true;
}
return bReturn;
}
int CCommuAnalyzer::IsExistDirtyData(char* pszNetRcvBufIn, int iNetRcvBufLenIn, int& iSkipLen)
{
int iReturn = 0;
iSkipLen = 0;
if ((iNetRcvBufLenIn - 2 > 0) && (pszNetRcvBufIn[0] != '\n' && pszNetRcvBufIn[1] != '\r') )
{
iReturn = -1;
std::cout<< "有脏数据,返回值: " << iReturn << ((iReturn == -1) ? ":清理脏数据":":中断网络") << std::endl;
int iScanPos = 0;
while(iNetRcvBufLenIn - iScanPos - 2> 0)
{
if (pszNetRcvBufIn[iScanPos] == '\n' && pszNetRcvBufIn[iScanPos+1] == '\r')
{
break;
}
iScanPos++;
}
iSkipLen = iScanPos;
}
return iReturn;
}
bool CCommuAnalyzer::IsHasFullPackage(char* pszNetRcvBufIn, int iNetRcvBufLenIn)
{
bool bReturn = false;
if (iNetRcvBufLenIn >= 6)
{
int iBodyLen = 0;
memcpy(&iBodyLen, (pszNetRcvBufIn + 2), sizeof(int));
iBodyLen = ntohl(iBodyLen);
if (iBodyLen <= iNetRcvBufLenIn - 6)
{
bReturn = true;
}
else
{
// std::cout<< "网络缓存数据不足" << std::endl;
}
}
else
{
// std::cout<< "网络缓存数据不足" << std::endl;
}
return bReturn;
}
bool CCommuAnalyzer::UnpackNetPackage(char* pszNetRcvBufIn, int iNetRcvBufLenIn, char*& pszBodyOut, int& iBodyLenOut, int& iHeadLenOut, int& iTailLenOut)
{
bool bReturn = false;
int iBodyLen = 0;
memcpy(&iBodyLen, (pszNetRcvBufIn + 2), sizeof(int));
iBodyLenOut = ntohl(iBodyLen);
iHeadLenOut = 6;
iTailLenOut = 0;
if (iBodyLenOut == 0)
{
pszBodyOut = NULL;
bReturn = true;
}
else
{
pszBodyOut = new char[iBodyLenOut + 1];
if (pszBodyOut == NULL)
{
std::cout<< "分配内存存储解包后的业务报文失败" << std::endl;
}
else
{
memset(pszBodyOut, 0x00, iBodyLenOut + 1);
memcpy(pszBodyOut, pszNetRcvBufIn + iHeadLenOut, iBodyLenOut);
}
}
return bReturn;
}