vlambda博客
学习文章列表

以官方例子开启我们的netty源码之旅

EchoClient类

EventLoopGroup group = new NioEventLoopGroup();
try {
    Bootstrap b = new Bootstrap();
    b.group(group)
     .channel(NioSocketChannel.class)
     .option(ChannelOption.TCP_NODELAY, true)
     .handler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception 
{
             ChannelPipeline p = ch.pipeline();
             if (sslCtx != null) {
                 p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
             }
             //p.addLast(new LoggingHandler(LogLevel.INFO));
             p.addLast(new EchoClientHandler());
         }
     });

    // Start the client.
    ChannelFuture f = b.connect(HOST, PORT).sync();

    // Wait until the connection is closed.
    f.channel().closeFuture().sync();
finally {
    // Shut down the event loop to terminate all threads.
    group.shutdownGracefully();
}

EchoServer类

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
     .channel(NioServerSocketChannel.class)
     .option(ChannelOption.SO_BACKLOG, 100)
     .handler(new LoggingHandler(LogLevel.INFO))
     .childHandler(new ChannelInitializer<SocketChannel>() {
         @Override
         public void initChannel(SocketChannel ch) throws Exception {
             ChannelPipeline p = ch.pipeline();
             if (sslCtx != null) {
                 p.addLast(sslCtx.newHandler(ch.alloc()));
             }
             p.addLast(new LoggingHandler(LogLevel.INFO));
             //p.addLast(new EchoServerHandler());
         }
     });

    // Start the server.
    ChannelFuture f = b.bind(PORT).sync();

    // Wait until the server socket is closed.
    f.channel().closeFuture().sync();
finally {
    // Shut down all event loops to terminate all threads.
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

使用总结

1、ServerBootstrap类用于创建服务端实例,Bootstrap用于创建客户端实例。
2、在服务端,基于NioEventLoopGroup类创建了bossGroup、workerGroup这两个EventLoopGroup。客户端基于NioEventLoopGroup创建了一个group。它们可以理解为Netty中的线程池。
3、服务端的channel是NioServerSocketChannel(包装了nio原生的ServerSocketChannel),客户端的channel是NioSocketChannel(包装了nio原生的SocketChannel)
4、服务端ServerBootstrap有handler、childHandler;而客户端Bootstrap只有handler。
5、handler在初始化时执行,childHandler在客户端成功connect后才执行。如果需要在客户端连接前的请求进行    handler处理,则需要配置handler(),如果是处理客户端连接之后的handler,则需要配置在childHandler()。
6、pipeline:handler可以指定多个(需要上面的ChannelInitializer类辅助),它们会组成了一个 pipeline,它们其实就类似拦截器的概念,每个NioSocketChannel或NioServerSocketChannel内部都会有个pipeline实例。
7、ChannelFuture:涉及到Netty中的异步编程,和JDK中的Future接口类似。
8、handler可以指定多个(需要上面的ChannelInitializer类辅助)

展望

就这样,一个简单的netty应用程序就写完了。程序虽然简单,但世上的netty程序大体都是这几步:客户端和服务端各自开启EventLoopGroup和Bootstrap。使用很简单,所以我不会讲如何使用,但越简单的api往往意味着越复杂的底层代码。虽然使用起来就上面这几步,但是对应的底层代码非常复杂,你不应该想着短短几天就能搞明白。没有高手指路,甚至你很长时间都不一定能弄清楚,底层到底是如何运作的,相比于原生的NIO又有哪些异同。本系列文章就是这个目的,让你用最短的时间弄清楚netty的底层原理。如果你日常的工作只是CRUD,这个过程完成之后,你不只对netty,对NIO、多线程、异步、线程模型的理解也会更深一个层次。