在之前的文章Netty 入门初体验简单介绍了 Netty 服务端和客户端的例子,下面依旧以Netty 服务端 demo 为例,来简单阐述下 Netty 的基本组件。
以Netty服务端的一个例子来阐述其中用到的基本组件,代码如下:
public 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>() { @Override 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(); } } } 复制代码
服务端创建流程:
NioEventLoopGroup
线程池 ServerBootStrap
的 channel
方法设置并绑定服务端 Channel ChannelPipeline
ChannelHandler
上面简述了服务端的创建流程,其中包含了 Netty的基本组件的使用,下面这张导图也简单的叙述了Netty各大组件的概念与作用
Channel是 Netty中的网络操作抽象类,对应JDK底层的Socket,它除了包含基本的I/O操作,如 bind(),connect(),read(),write()之外,还包括了Netty框架相关的一些功能,如获取 Channel的EventLoop。
EventLoop定义了Netty的核心抽象, 用于处理连接的生命周期中所发生的事件 。EventLoop 为Channel处理I/O操作,下图是 Channel,EventLoop,Thread以及EventLoopGroup之间的关系(摘自《Netty In Action》):
这些关系是:
EventLoopGroup实际上就是处理I/O操作的线程池,负责为每个新注册的Channel分配一个EventLoop,Channel在整个生命周期都有其绑定的 EventLoop来服务。
而上面服务端用的 NioEventLoop 就是 EventLoop的一个重要实现类,NioEventLoop 是Netty内部的I/O线程,而 NioEventLoopGroup 是拥有 NioEventLoop 的线程池,在Netty服务端中一般存在两个这样的 NioEventLoopGroup 线程池,一个 "Boss" 线程池,用于接收客户端连接,实际上该线程池中只有一个线程,一个 "Worker"线程池用于处理每个连接的读写。而Netty客户端只需一个线程池即可,主要用于处理连接中的读写操作。
ChannelHandler是Netty的主要组件,它主要用于对出站和入站数据进行处理,它有两个重要的子接口:
ChannelPipeline提供了 ChannelHandler链的容器,换句话说,就是一个逻辑处理链,用于 拦截 流经Channel的入站和出站事件的 ChannelHandler 。还是就是当 Channel被创建时,它会被自动地分配到它的专属的 ChannelPipeline。
当一个消息或者任何其他的入站事件被读取时,那么它会从 ChannelPipeline的头部开始流动,并被传递给第一个 ChannelInboundHandler,第一个处理完成之后传递给下一个 ChannelInboundHandler,一直到ChannelPipeline的尾端,与之对应的是,当数据被写出时,数据从 ChannelOutboundHandler 链的尾端开始流动,直到它到达链的头部为止。
Netty中所有I/O操作都是异步的,使用ChannelFuture可以获取操作完成的结果,其 addListener()
方法注册了一个 ChannelFutureListener,以便在某个操作完成时(无论是否成功)得到通知。
ByteBuf是Netty中的字节缓冲区,相比于Java NIO中的 ByeBuffer,ByteBuf做了很多改进,ByteBuf的功能性和灵活性更好。
Netty提供的启动辅助类,帮助Netty客户端或服务端的Netty初始化,服务端对应的是 ServerBootStrap引导类。