有时候发送的数据过长,接收的时候只接收了一部分,会出现错误。这里以客户端接收服务端消息为例,讲解一种解包的方法,作为备忘(总是忘没办法)

1.客户端有一段缓冲区char m_szAnalysisBuf[51200] 成员变量,用于存放接收数据,在回调函数收到数据后,判断缓冲区是否满了(一般不会满),未满的话将新接收的数据加入到缓冲区中,并更新缓冲区长度。如果缓冲区满了,则舍弃掉原缓冲区的数据,将新的数据加入缓冲区。

2.循环解包,首先我们要保证,起始的位置就是包头位置,前面的数据均为垃圾数据,因为每次截取一个完整包之后,理论上接下来的数据应该就是包头。进入AnalysisPacket函数,这里查找包头位置,如果没有找到,保留最后的(IMAH_XML_START_LEN-1)个字符,并移动到开始位置,其他的数据清空,如果找到了,但是不在缓冲区的起始位置,就把缓冲区包头前边的垃圾数据清空,保证起始位置就是包头。然后查找数据包结束位置,如果找到了,返回完整数据包起始位置,如果未找到,继续接收数据,并再次查找数据包结束位置,直到找到完整数据包,或缓冲区满。

这样可以保证,缓冲区开始位置就是数据包开始位置,如果缓冲区内找到数据包结束位置,就返回一个完整数据包,剩下的缓冲区数据继续查找,删除掉垃圾数据,继续保证缓冲开始位置为数据包起始位置,如此循环;如果没有找到结束位置,就继续接收,直到找到完整数据包。

这样就可以每次解析一个完整的数据包了,代码如下。

还要注意,如果解析出的完整包是错误信息,跳过PraseData后记得移除这段数据。

///< 处理客户端接收的数据
int CImahConfigTcpClient::TcpClientRecvData(int nTcpClientID,const char *pServerIP, int nServerPort, const char *pData, unsigned int uiDataLen)
{int nRet = 0;bool bRet = false;int nPocketEndPos = 0;          // 数据结尾位置IMAH_MSG_HEADER stMsgHeader;    // 消息头// 如果解析缓冲区未满,将数据复制到解析缓冲区if ((m_nAnalysisDataLen + uiDataLen) <= sizeof(m_szAnalysisBuf)){memcpy(&m_szAnalysisBuf[m_nAnalysisDataLen], pData, uiDataLen);m_nAnalysisDataLen += uiDataLen;}else // 如果解析缓冲区满了,舍弃解析缓冲区原来的数据,将新数据复制到解析缓冲区{g_logHostCfg.Log(JN_WARN, "TcpClientRecvData analysis buf is full. lost data:%d", m_nAnalysisDataLen);memset(m_szAnalysisBuf, 0, sizeof(m_szAnalysisBuf));memcpy(&m_szAnalysisBuf[0], pData, uiDataLen);m_nAnalysisDataLen = uiDataLen;}//g_logHostCfg.Log(JN_DEBUG, "len:%d buf:%s", uiDataLen, pData);// 循环解析数据包,// 有可能接收到的数据可以解析出来多个数据包,所以要循环,每次解析出来一个数据包while (true){nPocketEndPos = 0;// 没有数据,跳出循环if (m_nAnalysisDataLen <= 0){break;}// 解析数据包nRet = Imah_AnalysisPacket(m_szAnalysisBuf, sizeof(m_szAnalysisBuf), m_nAnalysisDataLen, nPocketEndPos);// 解析数据失败,跳出循环if (nRet != 0){break;}// 未找到完整的数据包,跳出循环if ((nPocketEndPos <= 0) || (nPocketEndPos > sizeof(m_szAnalysisBuf))){break;}memset(&stMsgHeader, 0, sizeof(stMsgHeader));// 找到一个完整的数据包,解析消息头nRet = Message_Decode_MsgHeader(m_szAnalysisBuf, nPocketEndPos, &stMsgHeader);if (nRet != 0){g_logHostCfg.Log(JN_ERROR, "TcpClientRecvData RnssGb_Decode_MsgHeader error. len:%d xml:%s",nPocketEndPos, m_szAnalysisBuf);}else{// 判断UUID、正在等待的信息命令类型,是否一致if ((m_strNowUuid.compare(stMsgHeader.szMsgUUID) == 0) &&(m_strRecvCmdType.compare(stMsgHeader.szCmdType) == 0)){// 解析xml数据ParseXmlData(stMsgHeader, nPocketEndPos);}}// 数据前移,去掉了已经复制出来的部分数据m_nAnalysisDataLen -= nPocketEndPos;if (m_nAnalysisDataLen <= 0){m_nAnalysisDataLen = 0;}else{memmove(m_szAnalysisBuf, &m_szAnalysisBuf[nPocketEndPos], m_nAnalysisDataLen);// 移动后,后面无效的数据清空memset(&m_szAnalysisBuf[m_nAnalysisDataLen], 0, nPocketEndPos);}}return nRet;
}

AnalysisData:

//----------------------------------------------------------
/**
*   RNSS消息完整数据包解析函数
*       根据一个数据包的开始、结束标识,解析出一个完整数据包。
*       完整数据包的开始位置就是pAnalysisBuf的开始位置,
*       完整数据包的结束位置是pAnalysisBuf的nPacketEndPos。
*       当nPacketEndPos为0时,表明没有解析出完整的数据包
*   @param[in/out]  pAnalysisBuf        解析数据缓冲区
*   @param[in]      uiAnalysisBufLen    解析数据缓冲区长度
*   @param[in/out]  nAnalysisDataLen    解析数据缓冲区中数据的长度
*   @param[out]     nPacketEndPos       解析后的数据包的结束位置
*   @return 成功返回    0
*   @return 失败返回    -1
*/
int Imah_AnalysisPacket(char *pAnalysisBuf, unsigned int uiAnalysisBufLen, int &nAnalysisDataLen, int &nPacketEndPos)
{int nRet = 0;try{// 检查参数if ((NULL == pAnalysisBuf) || (uiAnalysisBufLen == 0)){
//             g_logProvData.Log(JN_WARN, "RnssGb_AnalysisPacket param error. buf:%s buflen:%d datalen:%d",
//                 pAnalysisBuf, uiAnalysisBufLen, nAnalysisDataLen);nPacketEndPos = 0;return 0;}// 没有数据if (nAnalysisDataLen <= 0){nPacketEndPos = 0;return 0;}int nStartPos = -1; // 数据包的开始位置// 查找数据包的开始位置for (int i = 0; i < (nAnalysisDataLen - IMAH_XML_START_LEN); i++){if (memcmp(pAnalysisBuf + i, IMAH_XML_START, IMAH_XML_START_LEN) == 0){nStartPos = i;break;}}// 没找到数据包的开始位置if (nStartPos < 0){// 保留最后的(IMAH_XML_START_LEN-1)个字符,并移动到开始位置,其他的数据清空if (nAnalysisDataLen > IMAH_XML_START_LEN){nStartPos = nAnalysisDataLen - (IMAH_XML_START_LEN - 1);nAnalysisDataLen -= nStartPos;memmove(pAnalysisBuf, pAnalysisBuf + nStartPos, nAnalysisDataLen);// 移动后,后面无效的数据清空memset(pAnalysisBuf + nAnalysisDataLen, 0, nStartPos);}nPacketEndPos = 0;return 0;}// 数据包的开始位置不在缓冲区的开始位置if (nStartPos > 0){// 丢掉垃圾数据,缓冲区的数据向前移动nAnalysisDataLen -= nStartPos;memmove(pAnalysisBuf, pAnalysisBuf + nStartPos, nAnalysisDataLen);// 移动后,后面无效的数据清空memset(pAnalysisBuf + nAnalysisDataLen, 0, nStartPos);}int nEndPos = 0;    // 数据包的结束位置// 查找数据包的结束位置for (int i = IMAH_XML_START_LEN; i <= (nAnalysisDataLen - IMAH_XML_END_LEN); i++){if (memcmp(pAnalysisBuf + i, IMAH_XML_END, IMAH_XML_END_LEN) == 0){nEndPos = i;break;}}// 没找到数据包的结束位置if (nEndPos < IMAH_XML_START_LEN){nPacketEndPos = 0;return 0;}// 找到了数据包的结束位置,设置完整数据包的结束位置nPacketEndPos = nEndPos + IMAH_XML_END_LEN;}catch (std::exception &ex){//g_logProvData.Log(JN_ERROR, "RnssGb_AnalysisPacket exception:%s", ex.what());nRet = -1;}return nRet;
}

网络传输粘包解包处理相关推荐

  1. python3 抓包 解包_Python结构包,解包

    python3 抓包 解包 Python struct module is capable of performing the conversions between the Python value ...

  2. Java版ISO8583报文组包/解包

    文章目录 一.8583协议简介 二.位图规则 三.8583格式报文参考 四.组包/解包思路 五.相关代码 一.8583协议简介   8583协议是基于ISO8583报文国际标准的包格式的通讯协议,85 ...

  3. C语言字符串的组包解包

    组包解包 sprintf组包 sscanf解包 sscanf的高级用法1:使用%*s %*d 跳过提取的内容(不要提取的内容) sscanf的高级用法2:使用%[n]s %[n]d 提取指定宽度n的字 ...

  4. 【各个模块间数据交互通讯及接口定义】串口通讯--压包解包,解析数据帧的方法

    系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录 前言 (1)ROS的分布式通信 (2)串口通讯--压包解包,解析数据帧的方 ...

  5. 网络传输——Base64详解

    网络传输--Base64详解 自从引用以来,Base64编码的标准极普及为的迅速.不过,把文件作为附件通过网际邮件扩充协议(MIME)传送时,Base64是标准的编码标准.然而,几乎所有的电子邮件客户 ...

  6. 网络粘包解包问题杂谈

    1.如何解决粘包问题? 在设计网络协议时,可能会存在粘包.丢包或者包乱序问题,但TCP协议时可靠性协议,大多数情况不存在丢包和乱序问题,但UDP协议如果不能接受少量丢包,就必须自己设计有序和可靠性传输 ...

  7. 解决TCP网络传输“粘包”问题

    当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport contro ...

  8. UNIX网络编程——解决TCP网络传输“粘包”问题

           当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport ...

  9. 解决TCP网络传输粘包问题

    作者:杨小平  王胜开 文章出处:http://blog.csdn.net/michelsn/archive/2008/01/02/2009894.aspx 当前在网络传输应用中,广泛采用的是TCP/ ...

最新文章

  1. AM消息中间件OA、ERP消息提醒的必要工具
  2. pytorch 网络可视化
  3. notepadpython插件_Notepad++插件Emmet和Python Script的安装
  4. C++ Unicode和ANSII转换
  5. python调用窗口找到文件,使用Python在Mac OS X中查找当前活动窗口
  6. Java笔记-通过注解和插件自动生成get/set和toString方法,使代码结构清晰
  7. html+css个人博客_如何在互联网放置 HTML 页面
  8. 形容时间过得快的句子,一些表示时间过得快的句子
  9. Oracle获取一年中的所有日期和一个月中的所有日期
  10. 【技术公开课】iOS App研发的最后冲刺:内测与部署
  11. win10家庭版 mysql_MySQL下载安装详解(win10家庭版)
  12. UART总线协议——esp32学习笔记
  13. PUBG 吃鸡排名预测
  14. 文件被占用删除不了?快来我给你一招解决!
  15. java对象强制类型转换,看完直接跪服
  16. 最新Exsi-6.7.0U3b版本下载
  17. c语言原地转10圈,[出圈]-题解(C语言代码)
  18. 建模师一个月的真实工资是多少
  19. 安卓打包出现“app:processReleaseManifest“问题的一种解决方案
  20. 反欺诈概念库-信用卡反欺诈管理

热门文章

  1. excel文字显示图标集_创建自己的Excel图标集
  2. 微信小程序遍历二维数组
  3. 吞吐量、带宽、bps、pps、转发能力、线速转发、交换带宽
  4. 【第4天】尊重是最有力的征服
  5. 尚融宝——阿里云短信验证功能(sms)
  6. 阿里云服务器部署app服务器端-流程步骤
  7. 计算机视觉在生物公司的应用,生物视觉仿生在计算机视觉中的应用研究.pdf
  8. 架构设计第三步:评估和选择备选方案
  9. hadoop支持lzo完整过程
  10. 工具使用技巧:将图片公式转为Word里的公式