[TOC]前言小故事很久很久以前,一位私塾先生到一家任教。双方签订了一纸协议:“无鸡鸭亦可无鱼肉亦可白菜豆腐不可少不得束修金”。此后,私塾先生虽然认真教课,但主人家则总是给私塾先生以白菜豆腐为菜,丝毫未见鸡鸭鱼肉的款待。私塾先生先是很不解,可是后来也就想通了:主人把鸡鸭鱼肉的钱都会换为束修金的,也罢。至此双方相安无事。年关将至,一个学年段亦告结束。私塾先生临行时,也不见主人家为他交付束修金,遂与主家理论。然主家亦振振有词:“有协议为证——无鸡鸭亦可,无鱼肉亦可,白菜豆腐不可少,不得束修金。这白纸黑字明摆着的,你有什么要说的呢?”私塾先生据理力争:“协议是这样的——无鸡,鸭亦可;无鱼,肉亦...
[TOC]一、概述长度域解码器(LengthFieldBasedFrameDecoder)是解决 TCP 拆包/粘包问题最常用的解码器。它基本上可以覆盖大部分基于长度拆包场景,开源消息中间件 RocketMQ 就是使用长度域解码器进行解码的。长度域解码器相比固定长度解码器和特殊分隔符解码器要复杂一些,接下来我们就一起学习下这个强大的解码器。二、重要属性长度域解码器特有属性// 长度字段的偏移量,也就是存放长度数据的起始位置 private final int lengthFieldOffset; // 长度字段所占用的字节数 private final int lengthField...
[TOC]一、解决方案短链接:发一个包建立一次连接,这样连接建立到连接断开之间就是消息的边界,缺点效率太低定长解码器:每一条消息采用固定长度,缺点浪费空间行解码器:每一条消息采用分隔符,例如 n,缺点需要转义LTC解码器:每一条消息分为 head 和 body,head 中包含 body 的长二、示例2.1 短链接客户端每次向服务器发送数据以后,就与服务器断开连接,此时的消息边界为连接建立到连接断开。这时便无需使用滑动窗口等技术来缓冲数据,则不会发生粘包现象。但如果一次性数据发送过多,接收方无法一次性容纳所有数据,还是会发生半包现象,所以短链接无法解决半包现象思路服务端:一次接收最大缓冲...
[TOC]一、粘包现象服务端代码import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.h...
[TOC]一、内存回收(retain & release)由于 Netty 中有堆外内存(直接内存)的 ByteBuf 实现,堆外内存最好是手动来释放,而不是等 GC 垃圾回收。UnpooledHeapByteBuf 使用的是 JVM 内存,只需等 GC 回收内存即可UnpooledDirectByteBuf 使用的就是直接内存了,需要特殊的方法来回收内存PooledByteBuf 和它的子类使用了池化机制,需要更复杂的规则来回收内存Netty 这里采用了引用计数法来控制回收内存,每个 ByteBuf 都实现了 ReferenceCounted 接口每个 ByteBuf 对象的初始计数为...
[TOC]一、ByteBuf组成ByteBuf由四部分组成说明ByteBuf 是一个字节容器,容器里面的的数据分为四个部分第一个部分是已经丢弃的字节,这部分数据是无效的;(已经读过的内容)第二部分是可读字节,这部分数据是 ByteBuf 的主体数据, 从 ByteBuf 里面读取的数据都来自这一部分;(已经写入但还未读取的内容)第三部分数据是可写字节,所有写到 ByteBuf 的数据都会写到这一段;(剩余可写入数据的空间大小)最后一部分表示的是该 ByteBuf 最多还能扩容多少容量上图中除了可扩容部分,剩下的内容是被两个指针给划分出来的,从左到右,依次是读指针(readerIndex)...
[TOC]一、概述ByteBuf是对NIO中ByteBuffer的增强。相比于ByteBuffer,Netty 的 ByteBuf 具有卓越的功能性和灵活性。ByteBuf API 的优点可以被用户自定义的缓冲区类型扩展通过内置的复合缓冲区类型实现透明的零拷贝容量可以按需增长在读和写这两种模式之间切换不需要调用 ByteBuffer 的 flip() 方法在读和写使用了不同的索引支持方法的链式调用支持引用计数支持池化二、工作原理ByteBuf 维护了两个不同的索引:一个用于读取,一个用于写入,当你从 ByteBuf 读取时,readIndex 会递增已经被读取的字节数。同样的,当你写入 ...
[TOC]一、概述ChannelHandler 用来处理 Channel 上的各种事件,分为入站、出站两种。所有 ChannelHandler 被连成一串,就是 Pipeline入站处理器通常是 ChannelInboundHandlerAdapter 的子类,主要用来读取客户端数据,写回结果;出站处理器通常是 ChannelOutboundHandlerAdapter 的子类,主要对写回结果进行加工。示例在这里,每个 Channel 是一个产品的加工车间,Pipeline 是车间中的流水线,ChannelHandler 就是流水线上的各道工序,而后面要讲的 ByteBuf 是原材料,经...
[TOC]一、概述Future与Promise在异步处理时,经常用到这两个接口首先要说明 netty 中的 Future 与 jdk 中的 Future 同名,但是是两个接口,netty 的 Future 继承自 jdk 的 Future,而 Promise 又对 netty Future 进行了扩展。jdk Future:只能同步等待任务结束(或成功、或失败)才能得到结果;netty Future:可以同步等待任务结束得到结果,也可以异步方式得到结果,但都是要等任务结束;netty Promise:不仅有 netty Future 的功能,而且脱离了任务独立存在,只作为两个线程间传递结...
[TOC]一、概述1.1 概念Channel是客户端和服务端建立的一个连接通道,是Netty抽象出来的网络I/O读写相关的接口。客户端有一个Channel(SocketChannel),服务端也有一个Channel(NioSocketChannel),当客户端和服务端建立连接后,客户端的Channel会跟服务端的Channel进行联通。1.2 Channel生命周期Channel的四个状态:状态描述channelUnregisteredChannel已经被创建,但还未注册到EventLoopchannelRegisteredChannel已经被注册到EventLoopchannelAct...