• TCP 粘包/拆包问题


    简介 

       TCP 是一个’流’协议,所谓流,就是没有界限的一串数据. 大家可以想想河里的流水,是连成一片的.期间并没有分界线, TCP 底层并不了解上层业务数据的具体含义 ,它会根据 TCP 缓冲区的实际情况进行包得划分,所以在业务上认为,一个完整的包可能会被 TCP 拆分成多个包进行发送 . 也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的 TCP 拆包和粘包.
     

    TCP 粘包/拆包问题说明

         我们可以通过图解对 TCP 粘包和拆包进行说明.粘包问题示例图:
     
     
    假设客户端分别发送了两个数据包 D1,D2 给服务端, 由于服务端一次读到的字节数是不确定的.故可能存在以下4种情况.
    1. 服务端分两次读取了两个独立的数据包. 分别是 D1,D2 ,没有粘包和拆包;
    2. 服务器一次收到两个数据包,D1和 D2粘在一起,被称为 TCP 的粘包;
    3. 服务器分两次读到两个数据包,第一次读到了完整的 D1包和D2的部分内容,第二次读取到了 D2包得剩余内容,这被称为 TCP 的拆包.
    4. 服务器分两次读到两个数据包,第一次读取到了 D1包得部分内容,第二次读取到了 D1包得剩余内容 D1_2和 D2包的整包.
     
         如果此时服务端的 TCP 接收滑窗非常小, 而且数据包D1和 D2比较大,很有可能出现第五种可能,即 服务端分多次才能将 D1和 D2包接收完全. 期间发生多次拆包.
     

    TCP 粘包/拆包发生的原因

         
         问题产生的原因有三个,分别如下.
    1. 应用程序 write 写入的字节大小大于套接字接口发送缓冲区大小;
    2. 进行 MSS 大小的 TCP 分段;
    3. 以太网帧的 payload 大于 MTU 进行 IP 分片;
     
    粘包问题的解决策略
         由于底层的 TCP 无法理解上层业务数据,所以在底层是无法保证数据包不被拆分和重组的 , 这个问题只能通过上层的应用协议栈设计来解决,根据业界主流的协议的解决方案, 可以归纳如下:
    1.      消息定长, 例如每个报文的大小固定长度200字节,如果不够,空位补齐空格;
    2.      在包尾部添加回车换行符进行分割, 例如 FTP 协议;
    3.      将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息具体长度)的字段,通常设计思路为消息头的第一个字段使用 int32 来表示消息的总长度;
    4.      更复杂的应用协议层;
     
     
     
     
     
  • 相关阅读:
    04.日志管理
    刷爆美国朋友圈的超燃短片:年轻人为什么要奋斗?
    【逗比作孽呀】网站缓存优化
    来看看这20个顶尖的开源项目!
    nginx处理问题笔记
    -bash: warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory
    一个创业公司倒下的128小时
    快速打造跨平台开发环境 vagrant + virtualbox + box
    【Git 使用笔记】第四部分:git在公司中的开发流程
    新购买的vps应该做的几件事情
  • 原文地址:https://www.cnblogs.com/mjorcen/p/4538929.html
Copyright © 2020-2023  润新知