zoukankan      html  css  js  c++  java
  • netty入门03

    目录(?)[+]

    这篇文章接着上一篇,分析一下Netty4的ServerBootstrp是如何工作的。

    EchoServer

    先看看Netty自带的EchoServer例子:

    1. /** 
    2.  * Echoes back any received data from a client. 
    3.  */  
    4. public class EchoServer {  
    5.   
    6.     private final int port;  
    7.   
    8.     public EchoServer(int port) {  
    9.         this.port = port;  
    10.     }  
    11.   
    12.     public void run() throws Exception {  
    13.         // Configure the server.  
    14.         EventLoopGroup bossGroup = new NioEventLoopGroup();  
    15.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
    16.         try {  
    17.             ServerBootstrap b = new ServerBootstrap();  
    18.             b.group(bossGroup, workerGroup)  
    19.              .channel(NioServerSocketChannel.class)  
    20.              .option(ChannelOption.SO_BACKLOG, 100)  
    21.              .handler(new LoggingHandler(LogLevel.INFO))  
    22.              .childHandler(new ChannelInitializer<SocketChannel>() {  
    23.                  @Override  
    24.                  public void initChannel(SocketChannel ch) throws Exception {  
    25.                      ch.pipeline().addLast(  
    26.                              //new LoggingHandler(LogLevel.INFO),  
    27.                              new EchoServerHandler());  
    28.                  }  
    29.              });  
    30.   
    31.             // Start the server.  
    32.             ChannelFuture f = b.bind(port).sync();  
    33.   
    34.             // Wait until the server socket is closed.  
    35.             f.channel().closeFuture().sync();  
    36.         } finally {  
    37.             // Shut down all event loops to terminate all threads.  
    38.             bossGroup.shutdownGracefully();  
    39.             workerGroup.shutdownGracefully();  
    40.         }  
    41.     }  
    42.   
    43.     public static void main(String[] args) throws Exception {  
    44.         int port;  
    45.         if (args.length > 0) {  
    46.             port = Integer.parseInt(args[0]);  
    47.         } else {  
    48.             port = 8080;  
    49.         }  
    50.         new EchoServer(port).run();  
    51.     }  
    52. }  

    可以看出,用法和Bootstrap差不多。

    作为Builder的ServerBootstrap

    1. public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {  
    2.   
    3.     private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();  
    4.     private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();  
    5.     private volatile EventLoopGroup childGroup;  
    6.     private volatile ChannelHandler childHandler;  
    7.     // ...  
    8. }  

    看代码可以知道,ServerBootstrap比它的超类多了四个Part,如下图所示:

    从bind()方法入手

    bind()方法实际上是在AbstractBootstrap里定义的,bind()先调用validate()方法检查各个Part是否准备就 绪,然后把工作交给了doBind()方法。doBind()方法首先调用initAndRegister()方法,然后把工作交给doBind0()。 initAndRegister()会调用模板方法init()来初始化Channel,initAndRegister()方法的细节上篇文章分析过了,这里不再复述。下面是整个方法调用过程的示意图:


    init()方法

    1. @Override  
    2. void init(Channel channel) throws Exception {  
    3.     final Map<ChannelOption<?>, Object> options = options();  
    4.     synchronized (options) {  
    5.         channel.config().setOptions(options);  
    6.     }  
    7.   
    8.     final Map<AttributeKey<?>, Object> attrs = attrs();  
    9.     synchronized (attrs) {  
    10.         for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {  
    11.             @SuppressWarnings("unchecked")  
    12.             AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();  
    13.             channel.attr(key).set(e.getValue());  
    14.         }  
    15.     }  
    16.   
    17.     ChannelPipeline p = channel.pipeline();  
    18.     if (handler() != null) {  
    19.         p.addLast(handler());  
    20.     }  
    21.   
    22.     final EventLoopGroup currentChildGroup = childGroup;  
    23.     final ChannelHandler currentChildHandler = childHandler;  
    24.     final Entry<ChannelOption<?>, Object>[] currentChildOptions;  
    25.     final Entry<AttributeKey<?>, Object>[] currentChildAttrs;  
    26.     synchronized (childOptions) {  
    27.         currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));  
    28.     }  
    29.     synchronized (childAttrs) {  
    30.         currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));  
    31.     }  
    32.   
    33.     p.addLast(new ChannelInitializer<Channel>() {  
    34.         @Override  
    35.         public void initChannel(Channel ch) throws Exception {  
    36.             ch.pipeline().addLast(new ServerBootstrapAcceptor(  
    37.                     currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));  
    38.         }  
    39.     });  
    40. }  


    ServerBootstrap类的init()方法虽然很长,但是却不难理解。首先是给Channel设置options和attrs,然后把User 提供的针对NioServerSocketChannel的Handler添加到Pipeline的末尾。接下来复制childOptions和 childAttrs,最后实例化一个ChannelInitializer,添加到Pipeline的末尾。init()方法执行完毕之 后,AbstractBootstrap的initAndRegister()方法会将NioServerSocketChannel注册到group 里。到此为止,NioServerSocketChannel的状态如下图所示:

    ChannelInitializer在channelRegistered事件触发后会调用initChannel()方法,随后把自己从Pipeline里删除:

    1. @Sharable  
    2. public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {  
    3.   
    4.     private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);  
    5.   
    6.     /** 
    7.      * This method will be called once the {@link Channel} was registered. After the method returns this instance 
    8.      * will be removed from the {@link ChannelPipeline} of the {@link Channel}. 
    9.      * 
    10.      * @param ch            the {@link Channel} which was registered. 
    11.      * @throws Exception    is thrown if an error occurs. In that case the {@link Channel} will be closed. 
    12.      */  
    13.     protected abstract void initChannel(C ch) throws Exception;  
    14.   
    15.     @SuppressWarnings("unchecked")  
    16.     @Override  
    17.     public final void channelRegistered(ChannelHandlerContext ctx)  
    18.             throws Exception {  
    19.         boolean removed = false;  
    20.         boolean success = false;  
    21.         try {  
    22.             initChannel((C) ctx.channel());  
    23.             ctx.pipeline().remove(this);  
    24.             removed = true;  
    25.             ctx.fireChannelRegistered();  
    26.             success = true;  
    27.         } catch (Throwable t) {  
    28.             logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);  
    29.         } finally {  
    30.             if (!removed) {  
    31.                 ctx.pipeline().remove(this);  
    32.             }  
    33.             if (!success) {  
    34.                 ctx.close();  
    35.             }  
    36.         }  
    37.     }  
    38. }  


    所以注册之后的NioServerSocketChannel状态如下图所示:

    ServerBootstrapAcceptor

    1. private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {  
    2.   
    3.     private final EventLoopGroup childGroup;  
    4.     private final ChannelHandler childHandler;  
    5.     private final Entry<ChannelOption<?>, Object>[] childOptions;  
    6.     private final Entry<AttributeKey<?>, Object>[] childAttrs;  
    7.   
    8.     @SuppressWarnings("unchecked")  
    9.     ServerBootstrapAcceptor(  
    10.             EventLoopGroup childGroup, ChannelHandler childHandler,  
    11.             Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {  
    12.         this.childGroup = childGroup;  
    13.         this.childHandler = childHandler;  
    14.         this.childOptions = childOptions;  
    15.         this.childAttrs = childAttrs;  
    16.     }  
    17.   
    18.     @Override  
    19.     @SuppressWarnings("unchecked")  
    20.     public void channelRead(ChannelHandlerContext ctx, Object msg) {  
    21.         Channel child = (Channel) msg;  
    22.   
    23.         child.pipeline().addLast(childHandler);  
    24.   
    25.         for (Entry<ChannelOption<?>, Object> e: childOptions) {  
    26.             try {  
    27.                 if (!child.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {  
    28.                     logger.warn("Unknown channel option: " + e);  
    29.                 }  
    30.             } catch (Throwable t) {  
    31.                 logger.warn("Failed to set a channel option: " + child, t);  
    32.             }  
    33.         }  
    34.   
    35.         for (Entry<AttributeKey<?>, Object> e: childAttrs) {  
    36.             child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());  
    37.         }  
    38.   
    39.         try {  
    40.             childGroup.register(child);  
    41.         } catch (Throwable t) {  
    42.             child.unsafe().closeForcibly();  
    43.             logger.warn("Failed to register an accepted channel: " + child, t);  
    44.         }  
    45.     }  
    46.     // ...  
    47. }  


    ServerBootstrapAcceptor在channelRead事件触发的时候(也就有客户端连接的时候),把childHandler加到 childChannel Pipeline的末尾,设置childHandler的options和attrs,最后把childHandler注册进childGroup,如下 图所示:

  • 相关阅读:
    Linux内核网络协议栈优化总纲
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 判断字符位置
    Java实现 蓝桥杯VIP 算法训练 链表数据求和操作
  • 原文地址:https://www.cnblogs.com/xdrlczj/p/5846067.html
Copyright © 2011-2022 走看看