前言
在之前的文章Netty 入门初体验简单介绍了 Netty 服务端和客户端的例子,下面依旧以Netty 服务端 demo 为例,来简单阐述下 Netty 的基本组件。
基本组件概览
以Netty服务端的一个例子来阐述其中用到的基本组件,代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[] args) throws InterruptedException {
new EchoServer(8888).start();
}
public void start() throws InterruptedException {
final EchoServerHandler serverHandler = new EchoServerHandler();
//创建EventLoopGroup,处理事件
EventLoopGroup group = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group,worker)
//指定所使用的NIO传输 Channel
.channel(NioServerSocketChannel.class)
//使用指定的端口设置套接字地址
.localAddress(new InetSocketAddress(port))
//添加一个EchoServerHandler到子Channel的ChannelPipeline
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
//EchoServerHandler别标志为@Shareable,所以我们可以总是使用同样的实例
socketChannel.pipeline().addLast(serverHandler);
}
});
//异步的绑定服务器,调用sync()方法阻塞等待直到绑定完成
ChannelFuture future = b.bind().sync();
future.channel().closeFuture().sync();
} finally {
//关闭EventLoopGroup,释放所有的资源
group.shutdownGracefully().sync();
worker.shutdownGracefully().sync();
}
}
}
服务端创建流程:
- 创建 ServerBootStrap实例
- 设置并绑定
NioEventLoopGroup
线程池 - 通过
ServerBootStrap
的channel
方法设置并绑定服务端 Channel - 创建并初始化
ChannelPipeline
- 添加并设置
ChannelHandler
- 绑定并启动监听端口
上面简述了服务端的创建流程,其中包含了 Netty的基本组件的使用,下面这张导图也简单的叙述了Netty各大组件的概念与作用
Channel
Channel是 Netty中的网络操作抽象类,对应JDK底层的Socket,它除了包含基本的I/O操作,如 bind(),connect(),read(),write()之外,还包括了Netty框架相关的一些功能,如获取 Channel的EventLoop。
EventLoop
EventLoop定义了Netty的核心抽象,用于处理连接的生命周期中所发生的事件。EventLoop 为Channel处理I/O操作,下图是 Channel,EventLoop,Thread以及EventLoopGroup之间的关系(摘自《Netty In Action》):
这些关系是:
- 一个EventLoopGroup 包含一个或者多个EventLoop
- 一个 EventLoop 在它的生命周期内只和一个Thread绑定
- 所有由 EventLoop处理的 I/O事件都将在它专有的Thread上被处理
- 一个 Channel 在它的生命周期内只注册一个EventLoop
- 一个 EventLoop 可能会被分配给一个或多个 Channel
EventLoopGroup实际上就是处理I/O操作的线程池,负责为每个新注册的Channel分配一个EventLoop,Channel在整个生命周期都有其绑定的 EventLoop来服务。
而上面服务端用的 NioEventLoop 就是 EventLoop的一个重要实现类,NioEventLoop 是Netty内部的I/O线程,而 NioEventLoopGroup是拥有 NioEventLoop的线程池,在Netty服务端中一般存在两个这样的NioEventLoopGroup线程池,一个 “Boss” 线程池,用于接收客户端连接,实际上该线程池中只有一个线程,一个 “Worker”线程池用于处理每个连接的读写。而Netty客户端只需一个线程池即可,主要用于处理连接中的读写操作。
ChannelHandler
ChannelHandler是Netty的主要组件,它主要用于对出站和入站数据进行处理,它有两个重要的子接口:
- ChannelInboundHandler——处理入站数据以及各种状态变化
- ChannelOutboundHandler——处理出站数据并且允许拦截所有的操作
ChannelPipeline
ChannelPipeline提供了 ChannelHandler链的容器,换句话说,就是一个逻辑处理链,用于拦截流经Channel的入站和出站事件的ChannelHandler。还是就是当 Channel被创建时,它会被自动地分配到它的专属的 ChannelPipeline。
当一个消息或者任何其他的入站事件被读取时,那么它会从 ChannelPipeline的头部开始流动,并被传递给第一个 ChannelInboundHandler,第一个处理完成之后传递给下一个 ChannelInboundHandler,一直到ChannelPipeline的尾端,与之对应的是,当数据被写出时,数据从 ChannelOutboundHandler 链的尾端开始流动,直到它到达链的头部为止。
ChannelFuture
Netty中所有I/O操作都是异步的,使用ChannelFuture可以获取操作完成的结果,其 addListener()
方法注册了一个 ChannelFutureListener,以便在某个操作完成时(无论是否成功)得到通知。
ByteBuf
ByteBuf是Netty中的字节缓冲区,相比于Java NIO中的 ByeBuffer,ByteBuf做了很多改进,ByteBuf的功能性和灵活性更好。
BootStrap
Netty提供的启动辅助类,帮助Netty客户端或服务端的Netty初始化,服务端对应的是 ServerBootStrap引导类。
小结
上面简单的介绍了Netty的一些基本组件,后续文章会详细对每个组件进行分析