• netty-bind


    ServerBootstrap在bind时,主要做了3个操作:init、register、bind

    init

     1 void init(Channel channel) throws Exception {
     2   final Map<ChannelOption<?>, Object> options = options0();
     3   synchronized (options) {
     4     setChannelOptions(channel, options, logger);
     5   }
     6 
     7   final Map<AttributeKey<?>, Object> attrs = attrs0();
     8   synchronized (attrs) {
     9     for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
    10       @SuppressWarnings("unchecked")
    11       AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
    12       channel.attr(key).set(e.getValue());
    13     }
    14   }
    15 
    16   ChannelPipeline p = channel.pipeline();
    17 
    18   final EventLoopGroup currentChildGroup = childGroup;
    19   final ChannelHandler currentChildHandler = childHandler;
    20   final Entry<ChannelOption<?>, Object>[] currentChildOptions;
    21   final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
    22   synchronized (childOptions) {
    23     currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
    24   }
    25   synchronized (childAttrs) {
    26     currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
    27   }
    28     //register后,ChannelInitializer的initChannel就会通过ChannelPipeline的fireChannelRegistered被调用,
    29     //initChannel方法返回后,ChannelInitializer会被从ChannelPipeline中删除。
    30     //pipeline.addLast(handler)会将我们设置的handler添加在pipeline中,如果我们添加的是一个ChannelInitializer,
    31     //执行完这个initChannel后,ChannelPipeline中就会有ChannelInitializer、ServerBootstrapAcceptor两个Handler,
    32     //registered事件继续在ChannelPipeline中传播,传至新添加的ChannelInitializer时,又会执行initChannel逻辑,
    33     //我们通常会在initChannel方法中进行添加handler操作,假设添加了h1、h2,
    34     //如果不通过execute执行添加ServerBootstrapAcceptor的操作(execute会将任务入队),
    35     //最后ChannelPipeline中就会有ServerBootstrapAcceptor、h1、h2。
    36   p.addLast(new ChannelInitializer<Channel>() {
    37     @Override
    38     public void initChannel(final Channel ch) throws Exception {
    39       final ChannelPipeline pipeline = ch.pipeline();
    40       ChannelHandler handler = config.handler();
    41       if (handler != null) {
    42         pipeline.addLast(handler);
    43       }
    44 
    45       ch.eventLoop().execute(new Runnable() {
    46         @Override
    47         public void run() {
    48             //ServerBootstrapAcceptor
    49           pipeline.addLast(new ServerBootstrapAcceptor(
    50                   ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
    51         }
    52       });
    53     }
    54   });
    55 }

    ServerBootstrapAcceptor主要就是将channel注册到selector上

     1 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {
     2     //......
     3     
     4     public void channelRead(ChannelHandlerContext ctx, Object msg) {
     5         //io.netty.channel.Channel,该channel是对jdk的channel的包装,
     6         //在serverSocket accept到socket后,socket就会被包装为io.netty.channel.Channel,
     7         //然后通过pipeline.fireChannelRead传到这里,目前这一系列操作都是在boss线程中进行的。
     8       final Channel child = (Channel) msg;
     9         //将childHandler添加到accept的channel上
    10       child.pipeline().addLast(childHandler);
    11 
    12       setChannelOptions(child, childOptions, logger);
    13 
    14       for (Entry<AttributeKey<?>, Object> e: childAttrs) {
    15         child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
    16       }
    17 
    18       try {
    19           //注册Channel,注册后channel就绑定在了特定的EventLoop上,
    20           //并且注册在与EventLoop对应的selector上,该channel之后的IO操作都是在EventLoop上进行的。
    21         childGroup.register(child).addListener(new ChannelFutureListener() {
    22           @Override
    23           public void operationComplete(ChannelFuture future) throws Exception {
    24             if (!future.isSuccess()) {
    25               forceClose(child, future.cause());
    26             }
    27           }
    28         });
    29       } catch (Throwable t) {
    30         forceClose(child, t);
    31       }
    32     }
    33     
    34     //......
    35 }

    register

    register和bind都涉及到一个接口io.netty.channel.Channel.Unsafe

     1 //Unsafe提供了提供了与真正的IO操作,比如从socket读数据、写数据,将channel注册到selector等。
     2 interface Unsafe {
     3     //......
     4     
     5     void bind(SocketAddress localAddress, ChannelPromise promise);
     6     
     7     void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
     8 
     9     void write(Object msg, ChannelPromise promise);
    10 
    11     void flush();
    12     
    13     /**
    14      * Schedules a read operation that fills the inbound buffer of the first {@link ChannelInboundHandler} in the
    15      * {@link ChannelPipeline}.  If there's already a pending read operation, this method does nothing.
    16      */
    17     void beginRead();
    18     
    19     /**
    20      * Register the {@link Channel} of the {@link ChannelPromise} and notify
    21      * the {@link ChannelFuture} once the registration was complete.
    22      */
    23     void register(EventLoop eventLoop, ChannelPromise promise);
    24      
    25     //......
    26 }
     1 //Unsafe实现的register方法,有删减
     2 public final void register(EventLoop eventLoop, final ChannelPromise promise) {
     3     //如果在worker线程中,则直接注册(即将channel注册在selector上)
     4     if (eventLoop.inEventLoop()) {
     5         register0(promise);
     6     } else {
     7         //如果不在worker线程中,则异步注册,如果worker线程未开启,execute会先开启线程再入队。
     8         eventLoop.execute(new Runnable() {
     9             @Override
    10             public void run() {
    11                 register0(promise);
    12             }
    13         });
    14     }
    15 }

    bind

    注册之后,就可以bind了,bind仍然会在eventLoop中执行,此后serverSocket就开始监听client请求了。

  • 相关阅读:
    第五周课堂测试补充
    20162327WJH2016-2017-2《程序设计与数据结构》课程总结
    20162327WJH实验五——数据结构综合应用
    20162327WJH实验四——图的实现与应用
    20162327 《程序设计与数据结构》第十一周学习总结
    20162327WJH第三次实验——查找与排序2
    20162327 《程序设计与数据结构》第九周学习总结
    20162327WJH第二次实验——树
    20162327 《程序设计与数据结构》第七周学习总结
    20162327WJH使用队列:模拟票务站台代码分析
  • 原文地址:https://www.cnblogs.com/holoyong/p/7436078.html
Copyright © 2020-2023  润新知