前言
从开始打算学Netty,然后很自然的找到了《Netty实战》这本书,但是,对一个从来没写过的Netty程序的人而言,理解书中的概念确实很难呀。更何况,还几乎没有Nio网络编程的基础,所以一度书看不下去,但觉得写Netty程序不算什么很难的事情。
后来,由于一些需要,自己开始写Netty服务端和客户端,时常出现服务端发不出去消息,或者客户端收不到消息。并且用的Kotlin,异常都没有受检,就更加找不到错误了。这时回过头来看看《Netty实战》才感觉收获很多。
Channel
代表一个通道,连接客户端和服务端两头,两头都可以往Channel里面写/读东西。且Channel的读写是线程安全的。
一个Channel与一个EventLoop绑定,而一个EventLoop可以视为一个线程,用于处理Channel的回调事件。
ChannelRegistered -> ChannelActive
|
\/
ChannelUnregistered <- ChannelInactive
由类图可以得到一些信息:Comparable接口保证Channel是独一无二的,AttributeMap有attr(AttrubuteKey< T >)和hasAttr(AttrubuteKey< T >)
通过localAddress()和remoteAddress()可以获取连接的信息,此外isXXX()很好理解,write(),read(),flush()也很常见。
此外很重要的是pipeline()和config()这两个方法, ChannelPipeline持有所有入站和出站的ChannelHandler. 而ChannelConfig,看下图吧
unsafe()返回一个Unsafe对象,可以更改Channel的基本信息,如bind一个新的端口,connect一个新的远程地址…
还有Channel的父接口ChannelOutboundInvoker, 根据文档,说明write()方法是通过代理ChannelHandlerContext对象来实现的
常用的Channel
名称 | 包名 | 描述 |
---|---|---|
NIO | io.netty.channel.socket.nio | 基于java.nio.channels的Selector |
Epoll | io.netty.channel.epoll | 使用jni的eqoll()和非堵塞io,只在Linux可用的特性,速度更快 |
OIO | io.netty.channel.socket.oio | 基于java.net的堵塞Stream实现 |
Local | io.netty.channel.local | 在VM内部的管道传输 |
Embedded | io.netty.channel.embedded | 多用于测试ChannelHandler |
ByteBuf
Netty的数据传输通过ByteBuf(抽象类)和ByteBufHolder(接口)来暴露。
相比于ByteBuffer而言,ByteBuf有以下优点:可自行扩展,复合缓冲器类型零拷贝,容量自动增长,读写切换不需要flip,读写使用不同的索引,支持链式调用,支持引用计数,支持池化。
Bytebuf有readerIndex和writerIndex, readerIndex不能超过可读的索引,否则会抛出异常。
缓冲区类型
堆缓冲区:分配释放很快,读写较慢
ByteBuf heapBuf = ...
if(heapBuf.hasArray()){ //只有堆缓存有支撑数组,判断是不是堆缓存
byte[] array = heapBuf.array(); //如果有,获取数组的引用
int offset = heapBuf.arrayOffset() + heapBuf.readerIndex();//计算第一个字节的偏移量
int length = heapBuf.readableBytes();