• 一种tcp传输json包时出现包不完整、粘包的解决方案


    1.场景介绍

    较大的json包在tcp发送时会分成多个包,接收端比较难判断包的完整性,和是否存在包粘连的问题

    json包不完整包存在粘连
    {"id":"001","name":"jsonPick"}{"id":"001","name":"jsonPick"}{"id":"001","name":"jsonPick"}

    2.解决方案

    1. 用正则表达式来验证json格式是否完整
    2. 验证不完整时,等待并拼接下个包直到完整为止
    3. 当存在粘包时,用正则表达式的方案提取完整包
    4. 当存在多个完整包时,用正则表达式的方案提取多个完整包

    下表为一个完整的json包、正则表达式和运行结果

    json内容{"id":"001","name":"jsonPick"}
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: 0

    0 : "{\"id\":\"001\",\"name\":\"jsonPick\"}"

    3.解决方案的多场景模拟

    1.包不完整

    json内容{"id":"001","name":"json
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: -1

    0 : ""

    2.完整包,前粘连

    json内容e":"jsonPick"}{"id":"001","name":"jsonPick"}
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: 14

    0 : "{\"id\":\"001\",\"name\":\"jsonPick\"}"

    3.完整包,后粘连

    json内容{"id":"001","name":"jsonPick"}{"id":"001","name":
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: 0

    0 : "{\"id\":\"001\",\"name\":\"jsonPick\"}"

    4.完整包,前后粘连

    json内容e":"jsonPick"}{"id":"001","name":"jsonPick"}{"id":"001","name":
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: 14

    0 : "{\"id\":\"001\",\"name\":\"jsonPick\"}"

    5.包中包

    json内容{
        "id": "001",
        "name": "{\"id\":\"001\",\"name\":\"jsonPick\"}"
    }
    正则表达式\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*
    运行结果

    begin: -1

    0 : ""

    限制于\w=Matches a word character (QChar::isLetterOrNumber(), QChar::isMark(), or '_').

    \w无法匹配"、{、}等字符,故无法处理包中包的情况

    4.总结

    1.正则表达式能有效的判断包的完整性

    2.正则表达式能在有粘包的前提下提取到完整的包

    3.不支持包中包

    附源码

    1. /**
    2. * \s 表示一个\t、一个\n等
    3. * \s Matches a whitespace character (QChar::isSpace()).
    4. * \s* 多个
    5. * \s+ 至少一个
    6. * \s{2} 两个
    7. * \s{1,2} 一个到两个
    8. * \w 表示一个字母、一个数字、一个汉字等
    9. * \w Matches a word character (QChar::isLetterOrNumber(), QChar::isMark(), or '_').
    10. * \w* 多个
    11. * \w+ 至少一个
    12. * \w{2} 两个
    13. * \w{1,2} 一个到两个
    14. * () 表示提取的位置
    15. */
    16. QString Output = R"(
    17. {
    18. "id": "001",
    19. "name": "jsonPick"
    20. }
    21. )";
    22. QRegExp rx(R"(\s*\{\s*"\w*\"\s*:\s*"\w*\"\s*,\s*"\w*\"\s*:\s*"\w*\"\s*\}\s*)");
    23. qDebug() << "begin:" << rx.indexIn(Output);
    24. QStringList qsl = rx.capturedTexts();
    25. for(int i = 0; i < qsl.count(); i++)
    26. {
    27. qDebug() << i << ": " << qsl.at(i);
    28. }
    29. return 1;

    运行结果

    begin: 0

    0 : "\n {\n \"id\": \"001\",\n \"name\": \"jsonPick\"\n }\n "

  • 相关阅读:
    Java阻塞队列中的异类,SynchronousQueue底层实现原理剖析
    GIT实践与常用命令---回退
    JAVA潮购购物网站计算机毕业设计Mybatis+系统+数据库+调试部署
    【Python入门五】第三方库(包)介绍
    职场生存----如何缓解尴尬
    Anthropic全球上线AI语言模型Claude 2;多模态系统:融合文本和图像的新前沿
    3.前端、后端环境的搭建
    25分钟详细解说c++搜索算法
    计算机毕业设计微信小程序地摊租赁管理平台
    微信小程序设计规范
  • 原文地址:https://blog.csdn.net/ch593030323/article/details/128146669