传送门
《Netty 实战》第1,2,3章
《Netty 实战》第4,5,6章
《Netty 实战》第7,8,9章
《Netty 实战》第10,11章
《Netty 实战》第12,13章
第4章 Netty-传输
-
传输迁移
原始Jdk API(阻塞与非阻塞不统一),NIO接口复杂,而Netty抽象了统一的接口,对OIO和NIO一视同仁.从demo可见仅EventLoopGroup与ServerSocketChannel类型不同. -
传输API-channel
channel-interfaces.png
a. channel 关联pipeline和channelConfig
channel-methods.png
b. pipeline,一直过滤器模式(Intercepting Filter)
c. Channel方法
-
内置的传输模型
netty-trans.pnga. NIO: 默认用的,提供了一个所以I/O操作的全异步实现(netty强大之处),复杂的异步操作由netty实现了,对用户隐藏.
status-changes.png
b. Epoll: 仅linux系统可用的高效nio.
c. Oio: 实际上,netty用异步模拟同步,保证了接口的一致
d. Local: 用于JVM内部通讯(无demo)
e. Embedded: 用于测试Handler(第9章) -
传输的用例: 应用程序需求与推荐传输方式
selected.png
第5章 Bytebuf-Netty数据容器
-
API(ByteBuf和ByteBufHolder)
优点:类型扩展,零拷贝,容量增长,无需flip,不同索引,链式调用,引用计数器,池化. -
ByteBuf类
a.工作原理: 维护两个不同索引(readIndex和WriteIndex),用一个Capacity控制容量的增长.
b. 使用模式: 堆缓冲区(heap),直接缓冲区(derected)-避免内存整理的JVM资源浪费,复合缓冲区(Composite) -
字节级操作:
ByteBuf.pnga. 随机访问: 传入索引即可=> getByte(i)
b. 顺序访问: ?与上面一样啊.
c. 可丢弃字节( 介于原标签到ReaderIndex之间),可被整理=>discardReadBytes
d. 可读字节(介于ReaderIndex和WriteIndex之间),readableBytes
e. 可写字节(介于WriteIndex和Capacity之间),writeableBYtes
f. 索引管理: mark,reset => clear()仅移动所有,不改内存,比discardReadBytes高效,也更不安全.
g. 查找操作: forEachByte(传入ByteProcessor)
h. 派生缓冲区: slice(),相当于一个内存有两套Index,高效(不需重新分配),冲突(无法感知另外一套读写),一般来说生成只读的派生缓冲区还是比较安全的
i. 读写操作(get/set,read/write)
j. 其他 -
ByteBufHolder接口, content(),copy(),duplicate()
-
ByteBuf分配
a. ByteBufAllocator接口,与使用模式有关(Pooled和Unpooled)
b. Unpooled缓冲方法
c. ByteBufUtil工具类(静态方法调用) -
引用计数ReferenceCounted
由于ByteBuf可能在堆外,因而Netty需要自行管理缓冲区,使用ReferenceCounted对活动对象的引用进行计数,当被引用的数量为0时,释放内存空间
第6章 ChannelHandler和ChannelPipeLine(重点章节)
channel负责网络连接,ByteBuf负责管理传输的内容,Handler负责处理业务逻辑.
-
ChannelHandler家族
a. 生命周期
channel-life.png
channel-life2.pngb. ChannelHandler的生命周期
channelhander-life.pngc. ChannelInboundHandler接口
channelinboundhandler-method.png显示资源分配/释放,一些内存位于直接内存,JVM没法管.SimpleChannelInboundHandler会自动释放资源,因此不应该存储指向任何消息的引用.
d. ChannelOutboundHandler接口
channeloutboundhandler-method.pngChannelPromise是ChannelFuture的子类,只有一次状态变更机会(和JS的一样啊)
e. ChannelHandler适配器
基本使用了空实现,继承时只需要关心要覆盖的方法
f. 资源管理
Netty使用引用计数器来处理池化的ByteBuf,因此调整引用计数器来管理对应的内存资源.
启动时:-Dio.netty.leakDectectionlevel=ADVANCED进行泄露检测.
入站消息被消费后,就不会传给下个InboundHandler了.
出站wreite后就需要release了,不应该在传给下个OutboundHandler了. -
ChannelPipeline接口:
channel与其Pipeline是在创建的时候关联的,无法改变.只能该Pipeline中的Handler.在Pipeline中传递消息时候,会自动判断下一个类型和事件方向是否匹配,不匹配自动跳过
pipeline-handler.pnga. 修改ChannelPipe的API
pipeline-methods.png由于Handler是在EventLoop线程中运行的,所以千万不要编写阻塞代码,否则整个Netty性能都受影响.如果有遗留代码,可以使用EventExecutorGroup新建线程(同样开销大).
b. 事件触发
出站/入站都有对应的fire××()方法,调用pipeLine向下个Handler流动. -
ChannelHandlerContext
ctx是Handler和Pipeline之间的关联,与Handler一一对应,从AbstractChannelHandlerContext可知,有prev,next,构成链条的地方.
a. ChannelHandlerContext使用
channel-relations.png实际上Channel或channelPipeLine上的事件是通过ChannelHandlerContext上调用完成的(整个链传播),而直接调用ctx可更加精细控制,只传播到下一个Handler.
ctx-eventline.png -
异常处理:
a. 入站异常,也会继续流动,直到Pipeline链有人caught处理
b. 出站异常,返回ChannelFuture->channelFutureListener,关心处理结果的自行判断处理
网友评论