深入理解Netty编解码、粘包拆包、心跳机制


深入理解Netty编解码、粘包拆包、心跳机制文章插图
本文作者:何建辉(公众号:org_yijiaoqian)
前言Netty系列文章:

  • BIO 、NIO 、AIO 总结
  • Unix网络编程中的五种IO模型
  • 深入理解IO多路复用实现机制
  • Netty核心功能与线程模型
前面我们讲了 BIO、NIO、AIO 等一些基础知识和Netty核心功能与线程模型 , 本篇重点来理解Netty的编解码、粘包拆包、心跳机制等实现原理进行讲解 。
Netty编解码Netty 涉及到编解码的组件有 Channel 、 ChannelHandler 、 ChannelPipe 等 , 我们先大概了解下这几个组件的作用 。
ChannelHandlerChannelHandler 充当来处理入站和出站数据的应用程序逻辑容器 。 例如 , 实现 ChannelInboundHandler 接口(或 ChannelInboundHandlerAdapter) , 你就可以接收入站事件和数据 , 这些数据随后会被你的应用程序的业务逻辑处理 。 当你要给连接的客户端发送响应时 , 也可以从 ChannelInboundHandler 刷数据 。 你的业务逻辑通常下在一个或者多个 ChannelInboundHandler 中 。
ChannelOutboundHandler 原理一样 , 只不过它是用来处理出站数据的 。
ChannelPipelineChannelPipeline 提供了 ChannelHandler 链的容器 。 以客户端应用程序为例 , 如果有事件的运动方向是从客户端到服务端 , 那么我们称这些事件为出站的 , 即客户端发送给服务端的数据会通过 pipeline 中的一系列 ChannelOutboundHandler (ChannelOutboundHandler 调用是从 tail 到 head 方向逐个调用每个 handler 的逻辑) , 并被这些 Hadnler 处理 , 反之称为入站的 , 入站只调用 pipeline 里的 ChannelInboundHandler 逻辑(ChannelInboundHandler 调用是从 head 到 tail 方向 逐个调用每个 handler 的逻辑 。 )
深入理解Netty编解码、粘包拆包、心跳机制文章插图
编解码器当你通过Netty发送或者接受一个消息的时候 , 就将会发生一次数据转换 。 入站消息会被解码:从字节转换为另一种格式(比如java对象);如果是出站消息 , 它会被编码成字节 。
Netty提供了一系列实用的编码解码器 , 它们都实现了ChannelInboundHadnler或者ChannelOutboundHandler接口 。 在这些类中 ,channelRead方法已经被重写了 。
以入站为例 , 对于每个从入站Channel读取的消息 , 这个方法会被调用 。 随后 , 它将调用由已知解码器所提供的decode()方法进行解码 , 并将已经解码的字节转发给ChannelPipeline中的下一个ChannelInboundHandler 。
Netty提供了很多编解码器 , 比如编解码字符串的StringEncoder和StringDecoder , 编解码对象的ObjectEncoder和ObjectDecoder 等 。
当然也可以通过集成ByteToMessageDecoder自定义编解码器 。
示例代码完整代码在 Github :
对应的包 com.niuh.netty.codec
Netty粘包拆包TCP 粘包拆包是指发送方发送的若干包数据到接收方接收时粘成一包或某个数据包被拆开接收 。 如下图所示 , client 发送了两个数据包 D1 和 D2 , 但是 server 端可能会收到如下几种情况的数据 。
深入理解Netty编解码、粘包拆包、心跳机制文章插图
程序演示首先准备客户端负责发送消息 , 连续发送5次消息 , 代码如下:
public void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i = 1; i <= 5; i++) {ByteBuf byteBuf = Unpooled.copiedBuffer("msg No" + i + " ", Charset.forName("utf-8"));ctx.writeAndFlush(byteBuf);}}然后服务端作为接收方 , 接收并且打印结果: