自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:
1.问题描述
socket通讯TCP协议虽然是稳定的通讯,但是也会出现丢包的现象,而且会出现一个数据包分几次发送的情况。所以需要用一个缓冲区去缓存数据,并且判断是不是一个完整的包。等接收到一个完整的数据包,然后再去处理解析。
2.解决方案
先要定一个特殊字符串,比如&#@!,这样四个字节的协议头,在你的通讯报文中绝对不会出现。然后在丢包之后,通过查找这四个字节的协议头,找到包开始的地方,将数据缺失的包过滤掉。找到这个协议头之后再去解析数据的长度,解析完数据数据长度,在缓存这个长度的包数据进行解析。一般是xml、json等格式的字符串字节流。只要读取指定长度的数据,进行数据解析即可。
3具体实现代码
结构定义
#define MAX_BUFFER_LENGTH (10*1024)
#define PROTOCOL_HEAD_LEN 12 //FAD 报文头长度
typedef struct
{
char gRecvBuff[TCP_RECV_DATA_LEN];
HPR_INT32 iBuffLen;
}BUFFER_INFO;
BUFFER_INFO m_stRecvBuf;//一次接收数据的缓存区
char m_pDataBuff[MAX_BUFFER_LENGTH];//每次接收的数据都放入这个缓冲区,空间更加,不断的处理接收
HPR_INT32 m_iDataLen;//总的数据长度
HPR_INT32 m_iOneFameLen;//一个数据包的数据长度,包括协议头、包长度和包数据
函数算法实现
HPR_INT32 CCuItem::ParseData(HPR_ULONG NumberOfBytes)
{
HPR_UINT16 iRetVal = HPR_ERROR;
if( NumberOfBytes<0)
{
LOG_ERROR("ParseDataFromUtdu Point is NULL");
return iRetVal;
}
LOG_INFO("Receive the data length is %d",NumberOfBytes);
int nOneFameLen=0;
if (NumberOfBytes > 0)//数据大于0
{
if ((m_iDataLen + NumberOfBytes) > MAX_BUFFER_LENGTH)//超出缓冲区大小,丢弃
{
HPR_ZeroMemory(m_pDataBuff,MAX_BUFFER_LENGTH);
m_iDataLen = 0;
m_iOneFameLen=0;
LOG_ERROR("DataBuff's length is more than MaxBuff!");
return HPR_ERROR;
}
else
{
memmove(m_pDataBuff+m_iDataLen, m_stRecvBuf.gRecvBuff,NumberOfBytes);//将数据放入缓冲区
m_iDataLen+=NumberOfBytes;
}
while (m_iDataLen>=HeaderLenth)//数据长度大于协议头长度
{
HPR_INT32 msgLen=0;
HPR_INT32 msgtype = 0;
HeaderPacket headPack;
memmove(&headPack,m_pDataBuff,HeaderLenth);//将协议头放入结构体头部
int msglen = headPack.lenth;//得到包数据长度
LOG_INFO("The xml length is %d",msgLen);
if(msgLen<0)
{
LOG_INFO("Parase the Data length is less then zero %d",msgLen);
return HPR_ERROR;
}
m_iOneFameLen= HeaderLenth +msgLen;//得到协议头和包数据的长度
LOG_INFO("One Frame length is %d",m_iOneFameLen);
if (m_pDataBuff[0]!='H'||m_pDataBuff[1]!='K'||m_pDataBuff[2]!='P'||m_pDataBuff[3]!='&')//判断协议头
{
LOG_ERROR("协议头错误,data:%s", m_pDataBuff);
//查找协议头
int i = 0;
for (i = 0; i < m_iDataLen&&i < MAX_BUFFER_LENGTH; i++)//如果前四个字节不是协议头,进入查找
{
if (m_pDataBuff[i] == 'H')
{
if ((i+1)>=m_iDataLen)//长度只有1 不够
{
break;
}
if (m_pDataBuff[i+1]=='K')
{
if ((i+2)>=m_iDataLen)//长度只有2 不够
{
break;
}
if (m_pDataBuff[i+2]=='P')
{
if ((i + 3) >= m_iDataLen)//长度只有3 不够
{
break;
}
if (m_pDataBuff[i + 3] == '&')
{
break;//找到协议头,跳出循环
}
}
}
}
}
//将databuff向前移动i位
memmove(m_pDataBuff, m_pDataBuff + i, m_iDataLen - i);//删除前面i个脏数据
m_iDataLen = m_iDataLen - i;//重新计算缓冲区数据长度
HPR_ZeroMemory(m_pDataBuff+ m_iDataLen,MAX_BUFFER_LENGTH- m_iDataLen);//将缓冲区后面的数据置零
m_iOneFameLen=0;
LOG_ERROR("Pro is wrong!\n");
}
else//头部是协议头,处理数据
{
if (m_iDataLen>=m_iOneFameLen)
{
ParseRecvMessage(headPack.type,m_pDataBuff+ HeaderLenth,m_iOneFameLen);
memmove(m_pDataBuff,m_pDataBuff+m_iOneFameLen,m_iDataLen-m_iOneFameLen);
m_iDataLen-=m_iOneFameLen;
HPR_ZeroMemory(m_pDataBuff+m_iDataLen,MAX_BUFFER_LENGTH-m_iDataLen);
}
else
{
LOG_INFO("The data is Less than oneFrame,keep recieve\n");
break;
}
}
}
}
return HPR_OK;
}
HPR_INT32 CCuItem::ParseData(HPR_ULONG NumberOfBytes)
{
HPR_UINT16 iRetVal = HPR_ERROR;
if( NumberOfBytes<0)
{
LOG_ERROR("ParseDataFromUtdu Point is NULL");
return iRetVal;
}
LOG_INFO("Receive the data length is %d",NumberOfBytes);
int nOneFameLen=0;
if (NumberOfBytes > 0)//数据大于0
{
if ((m_iDataLen + NumberOfBytes) > MAX_BUFFER_LENGTH)//超出缓冲区大小,丢弃
{
HPR_ZeroMemory(m_pDataBuff,MAX_BUFFER_LENGTH);
m_iDataLen = 0;
m_iOneFameLen=0;
LOG_ERROR("DataBuff's length is more than MaxBuff!");
return HPR_ERROR;
}
else
{
memmove(m_pDataBuff+m_iDataLen, m_stRecvBuf.gRecvBuff,NumberOfBytes);//将数据放入缓冲区
m_iDataLen+=NumberOfBytes;
}
while (m_iDataLen>=HeaderLenth)//数据长度大于协议头长度
{
HPR_INT32 msgLen=0;
HPR_INT32 msgtype = 0;
HeaderPacket headPack;
memmove(&headPack,m_pDataBuff,HeaderLenth);//将协议头放入结构体头部
int msglen = headPack.lenth;//得到包数据长度
LOG_INFO("The xml length is %d",msgLen);
if(msgLen<0)
{
LOG_INFO("Parase the Data length is less then zero %d",msgLen);
return HPR_ERROR;
}
m_iOneFameLen= HeaderLenth +msgLen;//得到协议头和包数据的长度
LOG_INFO("One Frame length is %d",m_iOneFameLen);
if (m_pDataBuff[0]!='H'||m_pDataBuff[1]!='K'||m_pDataBuff[2]!='P'||m_pDataBuff[3]!='&')//判断协议头
{
LOG_ERROR("协议头错误,data:%s", m_pDataBuff);
//查找协议头
int i = 0;
for (i = 0; i < m_iDataLen&&i < MAX_BUFFER_LENGTH; i++)//如果前四个字节不是协议头,进入查找
{
if (m_pDataBuff[i] == 'H')
{
if ((i+1)>=m_iDataLen)//长度只有1 不够
{
break;
}
if (m_pDataBuff[i+1]=='K')
{
if ((i+2)>=m_iDataLen)//长度只有2 不够
{
break;
}
if (m_pDataBuff[i+2]=='P')
{
if ((i + 3) >= m_iDataLen)//长度只有3 不够
{
break;
}
if (m_pDataBuff[i + 3] == '&')
{
break;//找到协议头,跳出循环
}
}
}
}
}
//将databuff向前移动i位
memmove(m_pDataBuff, m_pDataBuff + i, m_iDataLen - i);//删除前面i个脏数据
m_iDataLen = m_iDataLen - i;//重新计算缓冲区数据长度
HPR_ZeroMemory(m_pDataBuff+ m_iDataLen,MAX_BUFFER_LENGTH- m_iDataLen);//将缓冲区后面的数据置零
m_iOneFameLen=0;
LOG_ERROR("Pro is wrong!\n");
}
else//头部是协议头,处理数据
{
if (m_iDataLen>=m_iOneFameLen)
{
ParseRecvMessage(headPack.type,m_pDataBuff+ HeaderLenth,m_iOneFameLen);
memmove(m_pDataBuff,m_pDataBuff+m_iOneFameLen,m_iDataLen-m_iOneFameLen);
m_iDataLen-=m_iOneFameLen;
HPR_ZeroMemory(m_pDataBuff+m_iDataLen,MAX_BUFFER_LENGTH-m_iDataLen);
}
else
{
LOG_INFO("The data is Less than oneFrame,keep recieve\n");
break;
}
}
}
}
return HPR_OK;
}