의 Netty 소스 분석 - 채널 (C) 만들기

        나는 인 Netty 시작 클래스를 보면

개인  공극 시작 () 가 발생 예외를 { 
        EventLoopGroup bossGroup = 새로운 NioEventLoopGroup를 (1 ); 
        EventLoopGroup workerGroup = 새로운 NioEventLoopGroup ( );
        시도 { 
            ServerBootstrap 부트 스트랩 = ) (ServerBootstrap을; 
            bootstrap.group (bossGroup, workerGroup) .channel (NioServerSocketChannel. 클래스 ) 
                    .option (ChannelOption.SO_BACKLOG, 128 ) 
                    .option (ChannelOption.SO_KEEPALIVE, 사실 )
                    .handler ( 새로운 LoggingHandler (LogLevel.INFO)) 
                    .localAddress는 ( 새로운 InetSocketAddress는 (포트)) 
                    .childHandler는 ( 새로운 ChannelInitializer <SocketChannel에> ()는 {
                         보호  공극 initChannel (SocketChannel에의 채널)이 발생 예외 { 
                            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 () 동기화 ().; 
        } 
    }

        의 Netty이 개 이벤트 루프 그룹 EventLoopGroup을 작성, 이것은 위에서 언급 한 모델 그룹이 멀티플렉서 채널 등록에 연결되어 새로운 클라이언트와 클라이언트 수신을 담당하는 첫 번째 이벤트의 듀티 사이클에 해당하는 것 위. 두 번째 책임은 읽기와 쓰기 등의 이벤트 루프 설정 클라이언트 이벤트를 처리하는 것입니다.

        의 Netty는 ServerBootstrap이 프로그래밍 코드의 체인이 함께 서버를 시작하는 방법, 매우 사용하기 쉽고 우아한를 사용합니다. 그래서 우리는 소스 코드를 살펴도의 Netty 소스 영리한 디자인 아이디어와 이해 방법, 우리 자신의 코드의 현명한 사용에 의해 쓰여진 좋은 기사를 읽은 것입니다. 다음으로, 소스 코드, 그리고 해석의 중요한 부분을 기록하고 강조합니다

        일견 그룹 방법 

공공 ServerBootstrap 그룹 (EventLoopGroup parentGroup, EventLoopGroup childGroup) {
         슈퍼 .group (parentGroup); // 첫번째 이벤트 사이클 그룹, 우리는이 그룹이 AbstractBootstrap와 푸 인 부모 클래스 메소드를 호출 계속하다 사이클의 상위 그룹 호출 그룹 멤버 변수 
IF (childGroup == ) { 드로 새로운 새 NullPointerException이 ( "childGroup ' ); } IF ( 이 본 .childGroup! = null이 {) 드로 새로운 새 IllegalStateException이가 ("childGroup가 이미 설정' ) } 이 본 .childGroup = childGroup; 제 일정주기를 설정 // 우리는 서브 사이클 기, 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 = () 동기화 (); // 여기에 바인드 () 내지

     방법은 doBind를 입력

개인 ChannelFuture doBind ( 최종 SocketAddress를 보이나 인근) {
         최종 ChannelFuture regFuture = initAndRegister ();  
        최종 채널 채널 = regFuture.channel ();
        경우 (! regFuture.cause는 () = 널 (null) ) {
             반환 regFuture을; 
        } 
        ...省略一大波代码
    }

     initAndRegister를 입력

최종 ChannelFuture initAndRegister () { 
        채널 채널 = ;
        시도 { 
            채널 = channelFactory.newChannel (); //这里就是创建一个父级的채널 
            INIT (채널); 
        } 캐치 (의 Throwable t) {
             경우 (! 채널 = null가 ) {
                 // newChannel (예 : SocketException이을 ( "열려있는 파일이 너무 많습니다")) 충돌하는 경우 채널은 null이 될 수 
                channel.unsafe ()를 closeForcibly ().;
                // 채널이 아직 등록되지 않기 때문에 우리는 GlobalEventExecutor의의 사용을 강제 할 필요가 
                수익을 새로운 DefaultChannelPromise (채널 GlobalEventExecutor.INSTANCE) .setFailure (t); 
            } 
            // 채널이 아직 등록되지 않기 때문에 우리는 GlobalEventExecutor의 사용을 강제 할 필요가 
            돌아가  새로운 (DefaultChannelPromise ) FailedChannel을 (GlobalEventExecutor.INSTANCE) .setFailure (t)를; 
        } 
      ...省略一大波代码
    }

 

 그게 내가 NioServerSocketChannel이 ReflectiveChannelFactory 공장 패키지를 사용 이전에 강조 왜이다지도는 여기에 있습니다. 그런 다음 ReflectiveChannelFactory를 입력 

 

인수가이 클래스의 인스턴스를하지와 NioServerSocketChannel는 생성자를 사용. 좋아, 우리가 NioServerSocketChannel 보면 인수 없음의 생성자입니다.

 기본 멀티플렉서 작성자 합격

의 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