boy-learning-netty | 08 Netty 是如何处理 TCP 粘包、半包等问题的

相关源码:boy-learning-netty
个人博客:http://bruce.bugmakers.club
内容来自《极客时间 - Netty源码剖析与实战》

Netty 是如何处理 TCP 粘包、半包等问题的

  • 什么是粘包和半包

  • 为什么 TCP 应用中会出现粘包和半包现象

  • 解决粘包和半包问题的集中常用方法

  • Netty 对三种常用封帧方式的支持

  • 解读 Netty 处理粘包、半包的源码

什么是粘包和半包

粘包

客户端多次发送 ABC, 服务端接收到 ABC? 如:ABCA, ABCAB, ABCABC

主要原因:

  • 发送方每次写入数据 < 套接字缓冲区大小
  • 接收方读取套接字缓冲区数据不及时

半包

客户端多次发送 ABC, 服务端接收到 A? B? 如:AB, BC, CA

主要原因:

  • 发送方每次写入数据 > 套接字缓冲区大小
  • 发送的数据大于协议的 MTU(Maximum Transmission Unit, 最大传输单元),必须拆包

换个角度看粘包和半包

  • 收发
    • 一个发送可能被多次接收,多个发送可能被一次接收
  • 传输
    • 一个发送可能占用多个传输包,多个发送可能公用一个传输包

为什么 TCP 应用中会出现粘包和半包现象

根本原因:

TCP 是流式协议,消息无边界。

提醒:UDP 像邮寄的包裹,虽然一次运输多个,但每个包裹都有“界限”,一个一个签收,所以无粘包、半包问题。

解决粘包和半包问题的集中常用方法

根本手段:找出消息的边界。

方式\比较 寻找消息边界的方式 优点 缺点 推荐度
TCP 连接改成短连接,一个请求一个短连接 建立连接到释放连接之间的信息即为传输信息 简单 效率低下 不推荐
封装成帧 Framing - 固定长度 满足固定长度即可 简单 浪费空间 不推荐
封装成帧 Framing - 分隔符 分隔符之间 空间不浪费,也比较简单 内容本身出现分隔符时需要转义,所以需要扫描内容,耗费资源 一般
封装成帧 Framing - 固定长度字段储存内容长度信息 先解析固定长度字段,再读取后续内容 精确定位用户数据,也不用转义 长度理论上有限制,需提前预知可能的最大长度从而定义长度占用字节数 推荐
封装成帧 Framing - 其他方式 每种都不同,如JSON可以看{}是否应已经成对 衡量实际场景 衡量实际场景 很多是对现有协议的支持

Netty 对三种常用封帧方式的支持

方式\支持 解码 编码
封装成帧 Framing - 固定长度 FixedLengthFrameDecoder 简单
封装成帧 Framing - 分隔符 DelimiterBasedFrameDecoder 简单
封装成帧 Framing - 固定长度字段储存内容长度信息 LengthFieldBasedFrameDecoder LengthFieldPrepender

解读 Netty 处理粘包、半包的源码

  • 解码核心工作流程
    ByteToMessageDecoder 入手

  • 解码中两种数据累计器(Cumulator)的区别

    第一种 MERGE_CUMULATOR(默认):内存复制
    第二种 COMPOSITE_CUMULATOR:逻辑视图

  • 三种解码器的常用额外控制参数有哪些

    长度
    分隔符(支持一个或多个)
    固定长度字段等

你可能感兴趣的:(boy-learning-netty | 08 Netty 是如何处理 TCP 粘包、半包等问题的)