ネッティーソース解析 - (C)チャンネルを作成します。

        私はネッティー開始クラスを見て

プライベート ボイド開始()はスロー例外{ 
        EventLoopGroup bossGroup = 新しい NioEventLoopGroup(1 )。
        EventLoopGroup workerGroup = 新しい NioEventLoopGroup();
        試す{ 
            ServerBootstrapブートストラップは = 新しいServerBootstrap(); 
            bootstrap.group(bossGroup、workerGroup).channel(NioServerSocketChannel。クラス
                    .OPTION(ChannelOption.SO_BACKLOG、 128 
                    (ChannelOption.SO_KEEPALIVE、.OPTION 
                    .handler(新しいLoggingHandler(LogLevel.INFO))
                    .localAddress(たInetSocketAddress(ポート))
                    .childHandler(新しい ChannelInitializer <たSocketChannel> (){
                         保護 ボイド initChannel(のSocketChannel CH)がスロー例外{ 
                            ch.pipeline()。addLast(新規の IdleStateHandler(5、0、0 、TimeUnit.MINUTES)); 
                            ch.pipeline(。)addLast(新しいProtobufVarint32FrameDecoder()); 
                            ch.pipeline()addLast(ProtobufDecoder(ChannelRequestProto.ChannelRequest.getDefaultInstance()))。
                            。ch.pipeline()addLast(新しいProtobufVarint32LengthFieldPrepender()); 
                            。ch.pipeline()addLast(新しいProtobufEncoder()); 
                            。ch.pipeline()addLast(新しいHeartBeatServerHandler()); 
                            。ch.pipeline()addLast(新しいXtsCoreServerHandler()); 
                        } 
                    })。
            ChannelFuture将来 = bootstrap.bind()同期()。
            。future.channel()closeFuture()同期()。
        } キャッチ(例外e){ 
            bossGroup.shutdownGracefully()同期()。
            。workerGroup.shutdownGracefully()同期(); 
        } 
    }

        ネッティー2つのイベントループグループEventLoopGroupを作成し、これは上記のモデルでは、グループはマルチプレクサチャネルレジスタに接続されている新しいクライアントとクライアントを受信するための責任がある最初のイベントのデューティサイクルに対応するであろう上記。第二の責任は、そのような読み出し、書き込みなどのイベントループ設定クライアントのイベントに対処するためです。

        ネッティーはServerBootstrapこのプログラミングコードのチェーンが一緒にサーバを起動する方法、および非常に使いやすいとエレガントを使用しています。だから我々は、ソースコードを見ても、ネッティーソース巧妙なデザインのアイデアや理解の方法、私たち自身のコードを巧みに使用して書かれた良い記事を読むために起こっています。次に、私は、ソースコード、および解釈の重要な一部を掲載して強調します

        Facie群法 

公共ServerBootstrap基(EventLoopGroup parentGroup、EventLoopGroup childGroup){
         スーパー.group(parentGroup); //最初のイベントサイクル基は、我々はグループであるサイクルの親グループは、AbstractBootstrapとフーある親クラスのメソッドを呼び出すために続けてそれを呼び出しますグループのメンバ変数に
IF(childGroup == NULL ){ スロー 新しい新規のNullPointerException( "childGroup" ); } IFこの .childGroup!= NULL ){ スロー 新しい新しい IllegalStateExceptionがが( "childGroupが既に設定" ); } この .childGroup = childGroup。 // 2番目のイベントサイクルを設定し、我々は直接メンバ変数のに割り当てられたサブサイクルグループ、childGroupそれを呼び出す リターン この; //自宅に戻り、これはチェーンプログラムの理由です }

       次はchannalタイプNioServerSocketChannel(もちろん、クライアントはNioSocketChannel)、再び特異バックに関連するインスタンスを作成するために反射の際に作成され、ここで使用される方法が提供され、チャネル法です。

公共の Bチャネル(クラス<?拡張 C> channelClass){
         IF(channelClass == nullの{)
             スロー 新しい新 NullPointerExceptionが( "channelClassを" ); 
        } 
        を返すのChannelFactory(新新 ReflectiveChannelFactory <C> (channelClassを)); // NioServerSocketChannelは使用 ReflectiveChannelFactoryを包装工場、およびAbstractBootstrapのに提供される
のChannelFactory //のメンバ変数、ここでの通知はchannal親channalです
}

      .OPTION方法はこちら.handler(新しいLoggingHandler(LogLevel.INFO))メソッドは、イベントループが設定されていることにより、親であると言うことではない親情報、当然のハンドラのいくつかのパラメータを設定することです。

.childHandler(新新 ChannelInitializer <のSocketChannel> (){// これはもちろん、サブグループのイベントループハンドラを提供しているが、この方法は、ここで呼び出すinitChannelないが、これは後に具体的に言及されます。
                         保護された 無効 initChannel(たSocketChannel CH)スロー例外{ 
                            ch.pipeline()addLast(新しい新。IdleStateHandler(5、0、0 、TimeUnit.MINUTESに))
                            。ch.pipeline()addLast(新しい新しいProtobufVarint32FrameDecoder()); 
                            。ch.pipeline()addLast(新しい新しいProtobufDecoder (ChannelRequestProto.ChannelRequest.getDefaultInstance())); 
                            。ch.pipeline()addLast(新新ProtobufVarint32LengthFieldPrepender())。
                            。ch.pipeline()addLast(新しいProtobufEncoder()); 
                            。ch.pipeline()addLast(新しいHeartBeatServerHandler()); 
                            。ch.pipeline()addLast(新しいXtsCoreServerHandler()); 
                        } 
                    })。

      さて、その後、正式な部分に。

ChannelFutureの未来= bootstrap.bind()syncは();. //ここにバインド()からです

     この方法は、doBindに入りました

プライベート ChannelFuture doBind(最終のSocketAddressをlocalAddress){
         最終 ChannelFuture regFuture = initAndRegister()。  
        最終チャネルチャネル= regFuture.channel()。
        もし(!regFuture.cause()= nullを){
             返すregFutureを。
        } 
        ...省略一大波代码
    }

     initAndRegisterを入力します。

最終ChannelFuture initAndRegister(){ 
        チャンネルチャネル = NULL ;
        試す{ 
            チャネル = channelFactory.newChannel()。//这里就是创建一个父级的チャネル
            INIT(チャンネル)
        } キャッチ(Throwableをトン){
             場合(チャネル=!ヌル){
                 // newChannel(例えばのSocketException( "あまりにも多くの開いているファイルを"))クラッシュした場合、チャネルはnullにでき
                channel.unsafe()closeForcibly();
                // チャンネルがまだ登録されていないとして、私たちはGlobalEventExecutorのの使用を強制する必要が
                リターンを 新しいDefaultChannelPromise(チャネル、GlobalEventExecutor.INSTANCE).setFailure(T); 
            } 
            // チャンネルがまだ登録されていないとして、私たちはGlobalEventExecutorの使用を強制する必要があります
            戻る 新しい DefaultChannelPromise(FailedChannel()、GlobalEventExecutor.INSTANCE).setFailure(t)を、
        } 
      ...省略一大波代码
    }

 

 それは私が以前NioServerSocketChannelがReflectiveChannelFactory工場出荷時のパッケージを使用強調し、なぜ、ここだマップ上にあります。そして、ReflectiveChannelFactoryを入力します。 

 

引数なしでコンストラクタを使用してNioServerSocketChannelは、このクラスをインスタンス化します。私たちはNioServerSocketChannelを見て[OK]を、引数なしのコンストラクタ。

 デフォルトのマルチプレクサの作成者を合格

ServerSocketChannelを作成するopenServerSocketChannel()メソッドを呼び出すためにそれを使用して、この特定の方法は、興味を持っているNIO内のコンテンツ、自分を見てとるがあります。

ここに戻るには、我々は(親レベルを使用して)チャネルが作成されます知って、ここを参照してください

大家千万不要忽视一点,这里有个this,我当时就没注意到这里,粗心了,导致其中有一步始终想不通,后来重新仔细看的时候,打自己的心都有了。

这里继续调用了另外一个有参的构造方法。

不断调用父类构造方法,就进入到

 

这里设置了父级的成员变量channel,并且把感兴趣的key设置为16(接收新的客户端),并且设置非阻塞。这里在第一篇启动NIO服务端的时候,也有这句,大家应该也记得。

我们继续看调用的父类构造方法。

我们知道了为Channel设置了一个ID,并且创建了Pipleline.并且初始化了两个上下文分别为头和尾,通过链表链接。

我们说到这里,简单回顾一下Pipeline. 我们开看下ChannelPipeline官方说明

讲到了, Pipeline 是 Channel中出站和入站操作的处理器或拦截器的一个列表。同时官方给出了一个表单我也贴出来

下图说明了I/O读写事件是怎么在PipeLine中的Handlers中传递的。需要通过 ChannelHandlerContext, 例如 ChannelHandlerContext#fireChannelRead(Object) 和  ChannelHandlerContext#write(Object)

这点了解Netty的一下子应该就看得明白,后面设计到PipeLine的地方我们再展开讲解,继续回到NioServerSocketChannel 的有参构造方法,继续往下看。

这里为刚刚创建的channel创建了一个配置类,并且是一个内部类。传入了channel和套接字。

不断往下跟,看到这里

这里传入了一个小内存分配器,也就是说为这个channel初始化了一个分配器。

ok,我们来简单说下这个分配器,后面在Netty的内存模型部分,我们再细说。

 

构造方法,传入了三个默认值,并且说明了 默认分配缓冲区的大小为1024 ,最小是64,最大是65536

通篇看一下,看到了一个非常重要的静态代码块

依次往sizeTable添加元素:[16 , (512-16)]之间16的倍数。即,16、32、48...496
然后再往sizeTable中添加元素:[512 , 512 * (2^N)),N > 1; 直到数值超过Integer的限制(2^31 - 1);
根据sizeTable长度构建一个静态成员常量数组SIZE_TABLE,并将sizeTable中的元素赋值给SIZE_TABLE数组。注意List是有序的,所以是根据插入元素的顺序依次的赋值给SIZE_TABLE,SIZE_TABLE从下标0开始。SIZE_TABLE为预定义好的以从小到大的顺序设定的可分配缓冲区的大小值的数组。因为AdaptiveRecvByteBufAllocator作用是可自动适配每次读事件使用的buffer的大小。这样当需要对buffer大小做调整时,只要根据一定逻辑从SIZE_TABLE中取出值,然后根据该值创建新buffer即可。

先了解这些,具体更加详细的内容,我们后面再介绍
 
好了,讲到这里,Channel创建完成。

 

 

おすすめ

転載: www.cnblogs.com/huxipeng/p/10747993.html
おすすめ