文章目录
1、ChannelHandlerContext Channel Pipeline
三者之间的关系如何?(TODO)
简单说:
ChannelHandlerContext
持有 Channel Pipeline
的引用;
Channel
和 Pipeline
互相持有对方的引用,也就是说 能互相 getXX 获取
Pipeline
本质上是个 双向链表
(TODO:更深刻的认识?)
2、Pipeline Channel NioEventLoop 关系
2、handler VS childHandler
bootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
// .handler()
.option(ChannelOption.SO_BACKLOG, 128)
.childHandler(new NettyHttpChannelInitializer())
.childOption(ChannelOption.SO_KEEPALIVE, true);
比较有疑惑的是,这里的 handler() 和 childHandler()
有啥区别?
- handler() 是针对 BossGroup 的,对NioServerSocketChannel 起作用
- childHanlder() 是针对WorkerGroup的,对的 NioSocketChannel起作用
3、Channel类型
Netty 中不同的协议类型和 Channel类型需要匹配上,列举几个常用的类型:
channel | 解释 |
---|---|
NioServerSocketChannel | 异步的服务端TCP Socket 连接 |
NioSocketChannel | 异步的客户端TCP socket连接 |
NioDatagramChannel | 异步的客户端UDP socket 连接 |
NioSctpChannel | 异步的客户端 SCTP socket 连接 |
NioSctpServerSocketChannel | 异步的服务端Sctp连接 |
4、Selector
Netty基于Selector 实现了 IO多路复用;
当向 Selector 注册了一个Channel时,Selector内部会不断轮询是否有已经就绪的IO事件,比如建立连接、IO读写,etc; 如此,一个Selector 可以管理很多个channel .
5、Handler
Handler用于处理或拦截IO事件,并将其传递给下一个 ChannelHandlerContext
。
ChannelHandlerContext
和 ChannelHandler
是一一对应的关系。ChannelPipeline
可以理解为 ChannelHandlerContext
的序列,如果是 Inbound
,事件 从 head --> tail
; 如果是 Outbound
,则从tail --> head
。
ChannelHandler
有十分复杂的继承结构(此处仅列举部分)
6、EventLoop
Netty最核心的抽象了。
看JavaDoc的描述:
Will handle all the I/O operations for a Channel once registered. One EventLoop instance will usually
handle more than one Channel but this may depend on implementation details and internals.
7、Unpooled类
JavaDoc的描述是:Creates a new ByteBuf by allocating new space or by wrapping or copying existing byte arrays, byte buffers and a string.
。也就是说, Unpooled
是个包含常用的静态方法的工具类。
有两类基本的操作:
Creating a wrapped buffer
Creating a copied buffer
8、ByteBuf
Netty中的核心数据容器。网络编程中经常要和字节(数组、序列)打交道,这个ByteBuf 就是一堆字节的缓冲区。
看Java doc的解释:
A random and sequential accessible sequence of zero or more bytes (octets). This interface provides an abstract view for one or more primitive byte arrays (byte[]) and NIO buffers.
BytebBuf
是可以随机或者顺序访问的字节序列。它提供了多个原始字节数组或NIO buffer 的抽象视图。
先来说下随机读:
ByteBuf buffer = ...;
for (int i = 0; i < buffer.capacity(); i ++) {
byte b = buffer.getByte(i);
System.out.println((char) b);
}
再来说下顺序读:顺序读涉及到了 ByteBuf
最核心的数据结构,ByteBuf底层有两个 指针,readerIndex writerIndex,顺序读写会移动指针。这也是为什么JDK自带的ByteBuffer
需要flip
,而Netty的 ByteBuf
可以直接获取可读写字节了。
+-------------------+------------------+------------------+
| discardable bytes | readable bytes | writable bytes |
| | (CONTENT) | |
+-------------------+------------------+------------------+
| | | |
0 <= readerIndex <= writerIndex <= capacity
9、ChannelOption
bootstrap.group(boss, worker)
.option(ChannelOption.SO_BACKLOG, 128)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyTimeHandler());
}
});
-
option(ChannelOption.SO_BACKLOG, 128)
ChannelOption.SO_BAKCLOG
对应到的是 服务端tcp/ip 协议中的 listen 函数的 backlog参数。listen 是初始化可连接队列的,服务端处理客户端的连接请求是 顺序处理的,同一时间只能处理同一个客户端连接,多个客户端请求连接的时候,会进入该队列等待。 这个参数指定了 队列的大小 -
.childOption(ChannelOption.SO_KEEPALIVE, true)
利用的是TCP的SO_KEEPALIVE
属性,若为true,服务端可以探测客户端是否还存活;假如客户端因为断电、关机等原因挂掉,服务端会关闭连接,释放资源。