自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:
https://www.cnblogs.com/bclshuai/p/11380657.html
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! "); } 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 "); 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! "); } 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 "); break; } } } } return HPR_OK; }