Netty4.x原始碼分析

苒翼發表於2020-11-15
一、基本元素整理

Bootstrap:Netty的啟動類
NioEventLoopGroup:負責處理事件,通過執行緒監聽selector處理讀、寫、連線
ChannelFuture:Netty大量使用了Future模式,既能同步也能非同步獲取結果
NioSocketChannel:所有Socket封裝成Channel進行讀寫
ChannelPipeline、ChannelHandler:採用責任鏈模式,ChannelPipeline將多個ChannelHandler串聯起來執行,ChannelHandler負責處理資料
StringDecoder、StringEncoder:負責字串的編解碼,是ChannelHandler的具體實現

二、呼叫示例
Bootstrap b = new Bootstrap();
b.group(new NioEventLoopGroup());
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<SocketChannel>() {
    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline ph = ch.pipeline();
        ph.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
        ph.addLast("decoder", new StringDecoder());
        ph.addLast("encoder", new StringEncoder());
        ph.addLast("handler", new HelloClientHandler()); // 客戶端的邏輯
    }
});

b.connect("127.0.0.1", 8000).addListener(new GenericFutureListener<ChannelFuture>() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
        if(!future.isSuccess()){
            future.cause().printStackTrace();
            return;
        }
        Channel ch =future.channel();
        final String str = "Hello Netty2";
        ch.writeAndFlush(str + "\r\n").addListener(new GenericFutureListener<ChannelFuture>() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if(!future.isSuccess()){
                    future.cause().printStackTrace();
                    return;
                }
                System.out.println("客戶端傳送資料:" + str);
            }
        });
    }
});
三、connect分析

3.1、呼叫javaChannel().register(eventLoop().unwrappedSelector(), 0, this);註冊selector
3.2、呼叫boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);建立連線
3.3、通過ChannelFuture返回結果

public ChannelFuture connect(String inetHost, int inetPort)
->return connect(InetSocketAddress.createUnresolved(inetHost, inetPort));
  ->return doResolveAndConnect(remoteAddress, config.localAddress());
    ->final ChannelFuture regFuture = initAndRegister();    --【Bootstrap】
      ->channel = channelFactory.newChannel();   --channelFactory是ReflectiveChannelFactory 通過反射建立channel【AbstractBootstrap】
      ->init(channel);
      ->ChannelFuture regFuture = config().group().register(channel);    --group是NioEventLoopGroup【AbstractBootstrapConfig】
        ->return next().register(channel);   --EventLoop是NioEventLoop【MultithreadEventLoopGroup】
          ->... 最終呼叫javaChannel
          ->selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);   --【AbstractNioChannel】
      ->return regFuture;    --regFuture是DefaultChannelPromise
   ->final Channel channel = regFuture.channel();    --【Bootstrap】
   ->final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
   ->regFuture.addListener(   --regFuture是DefaultChannelPromise
     @Override
     public void operationComplete(ChannelFuture future)   --【Bootstrap】
        ->promise.registered();   --【Bootstrap】
          ->registered = true;
        ->doResolveAndConnect0(channel, remoteAddress, localAddress, promise);   --【Bootstrap】
          ->final EventLoop eventLoop = channel.eventLoop();  --【Bootstrap】
          ->final AddressResolver<SocketAddress> resolver = this.resolver.getResolver(eventLoop);
          ->final Future<SocketAddress> resolveFuture = resolver.resolve(remoteAddress);  --【Bootstrap】
          ->resolveFuture.addListener(new FutureListener<SocketAddress>() {
            @Override
            public void operationComplete(Future<SocketAddress> future) throws Exception {   --丟到非同步執行緒請求,防止阻塞
              ->doConnect(future.getNow(), localAddress, promise);
                ->final Channel channel = connectPromise.channel();
                ->channel.eventLoop().execute(new Runnable() {   --eventLoop是NioEventLoop,繼承SingleThreadEventExecutor【Bootstrap】
                  ->public void run() {
                    ->channel.connect(remoteAddress, localAddress, connectPromise);  --【Bootstrap】
                      ->boolean connected = SocketUtils.connect(javaChannel(), remoteAddress);  --javaChannel是SocketChannel
                        ->return socketChannel.connect(remoteAddress);
四、write分析

4.1、客戶端呼叫this.addTask(task);將msg封裝成task丟到EventLoop中非同步執行
4.2、非同步執行緒呼叫this.write(this.ctx, this.msg, this.promise);往伺服器傳送資料
4.3、通過ChannelFuture返回傳送結果

ChannelFuture writeAndFlush(Object msg)
->return this.pipeline.writeAndFlush(msg);    //AbstractChannel 
  ->return this.tail.writeAndFlush(msg);   //DefaultChannelPipeline 
    ->return this.writeAndFlush(msg, this.newPromise());  //AbstractChannelHandlerContext 
      ->this.write(msg, true, promise);  //AbstractChannelHandlerContext 
        ->AbstractChannelHandlerContext next = this.findContextOutbound();
          ->do while(!ctx.outbound)
            ->ctx = ctx.prev;
         ->return ctx;   
       ->task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise);  //AbstractChannelHandlerContext 
         ->init(task, ctx, msg, promise);
           ->task.ctx = ctx;
           ->task.msg = msg;
           ->ctx.pipeline.incrementPendingOutboundBytes((long)task.size);
         ->return task;
       ->safeExecute(executor, (Runnable)task, promise, m);  //AbstractChannelHandlerContext 
         ->executor.execute(runnable);
           ->this.startThread();
           ->this.addTask(task);
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {
    abstract static class AbstractWriteTask implements Runnable {
        this.write(this.ctx, this.msg, this.promise);
        ->super.write(ctx, msg, promise);   //WriteAndFlushTask
          ->ctx.invokeWrite(msg, promise);  //AbstractWriteTask 
            ->this.invokeWrite0(msg, promise);    //AbstractChannelHandlerContext 
              ->((ChannelOutboundHandler)this.handler()).write(this, msg, promise);    //AbstractChannelHandlerContext 
                ->this.encode(ctx, cast, out);   //MessageToMessageEncoder
                  ->out.add(ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(msg), this.charset));  //StringEncoder
               ->ctx.write(out.get(0), promise);   //MessageToMessageEncoder
                 ->this.write(msg, false, promise);   //AbstractChannelHandlerContext 
                   ->AbstractChannelHandlerContext next = this.findContextOutbound();   //AbstractChannelHandlerContext 
                   ->next.invokeWrite(m, promise);   //AbstractChannelHandlerContext 
                     ->this.invokeWrite0(msg, promise);   //AbstractChannelHandlerContext 
                       ->((ChannelOutboundHandler)this.handler()).write(this, msg, promise);   //AbstractChannelHandlerContext 
                         ->this.unsafe.write(msg, promise);   //DefaultChannelPipeline.HeadContext
                           ->outboundBuffer.addMessage(msg, size, promise);
        ->ctx.invokeFlush();   //WriteAndFlushTask
          ->this.invokeFlush0();  //AbstractChannelHandlerContext
            ->((ChannelOutboundHandler)this.handler()).flush(this);  //AbstractChannelHandlerContext
              ->ctx.flush();   //ChannelOutboundHandlerAdapter
                ->next.invokeFlush();  //AbstractChannelHandlerContext
                  ->this.invokeFlush0();  //AbstractChannelHandlerContext
                    ->((ChannelOutboundHandler)this.handler()).flush(this);
                      ->this.unsafe.flush();
                        ->this.flush0();    //AbstractChannel 
                          ->AbstractChannel.this.doWrite(outboundBuffer);    //AbstractChannel 
                            ->while(true)
                              ->java.nio.channels.SocketChannel ch = this.javaChannel();
                              ->int localWrittenBytes = ch.write(nioBuffer);
    }
}
五、read分析

5.1、NioEventLoop通過迴圈監聽SelectionKey.OP_READ,通過NioSocketChannel接收訊息
5.2、ChannelHandler在非同步執行緒中接收並處理資料

public final class NioEventLoop extends SingleThreadEventLoop {
    protected void run() {
        for (;;) {
            switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
                case SelectStrategy.SELECT:
                    select(wakenUp.getAndSet(false));
                    if (wakenUp.get()) {
                        selector.wakeup();
                    }
            }
            processSelectedKeys();
            ->processSelectedKeysOptimized();
              ->final Object a = k.attachment();
              ->processSelectedKey(k, (AbstractNioChannel) a);
                ->final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();
                ->if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0)
                  ->unsafe.read();
        }
    }
}
public abstract class AbstractNioByteChannel extends AbstractNioChannel {
    protected class NioByteUnsafe extends AbstractNioUnsafe {
        public final void read() {
            final ChannelPipeline pipeline = pipeline();
            do {
                pipeline.fireChannelRead(byteBuf);
                ->AbstractChannelHandlerContext.invokeChannelRead(head, msg);   //DefaultChannelPipeline
                  ->
            } while (allocHandle.continueReading());
        }
    }
}
abstract class AbstractChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext, ResourceLeakHint {
    static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelRead(m);
            ->((ChannelInboundHandler) handler()).channelRead(this, msg);
              ->ctx.fireChannelRead(msg);   //DefaultChannelPipeline.HeadContext
                ->invokeChannelRead(findContextInbound(), msg);
                  ->next.invokeChannelRead(m);   //迴圈呼叫next.invokeChannelRead(m)
                   ->((ChannelInboundHandler) handler()).channelRead(this, msg);
                     ->ByteBuf data = (ByteBuf) msg;   //ByteToMessageDecoder
                     ->callDecode(ctx, cumulation, out);   //ByteToMessageDecoder
                       ->while (in.isReadable())   //ByteToMessageDecoder
                         ->fireChannelRead(ctx, out, outSize);   //ByteToMessageDecoder
                           ->fireChannelRead(ctx, (CodecOutputList) msgs, numElements);
                             ->for (int i = 0; i < numElements; i ++)
                               ->ctx.fireChannelRead(msgs.getUnsafe(i));   //ByteToMessageDecoder
                                 ->invokeChannelRead(findContextInbound(), msg);  //AbstractChannelHandlerContext
                                   ->next.invokeChannelRead(m);   //AbstractChannelHandlerContext
                                     ->((ChannelInboundHandler) handler()).channelRead(this, msg);
                                       ->decode(ctx, cast, out);   //MessageToMessageDecoder
                                         ->out.add(msg.toString(charset));  //StringDecoder
                                       ->ctx.fireChannelRead(out.getUnsafe(i));
                                         ->invokeChannelRead(findContextInbound(), msg);
                                           ->next.invokeChannelRead(m);  //AbstractChannelHandlerContext
                                             ->((ChannelInboundHandler) handler()).channelRead(this, msg);
                                               ->channelRead0(ctx, imsg);   //SimpleChannelInboundHandler
                                                 ->System.out.println("客戶端接受的訊息: " + msg);   //HelloClientHandler
        } else {
            executor.execute(new Runnable() {
                public void run() {
                    next.invokeChannelRead(m);
               }
            })
        }
    }
}

相關文章