Netty 概述

jopen 10年前發布 | 84K 次閱讀 Netty 網絡工具包

Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

異步的、事件驅動的網絡應用程序框架

Channel

Channel是Netty最核心的接口,一個Channel就是一個聯絡Socket的通道,通過Channel,你可以對Socket進行各種操作。

ChannelHandler

用Netty編寫網絡程序的時候,你很少直接操縱Channel,而是通過ChannelHandler來間接操縱Channel。

Netty中的所有handler都實現自ChannelHandler接口。按照輸出輸出來分,分為ChannelInboundHandler、ChannelOutboundHandler兩大類

ChannelInboundHandler對從客戶端發往服務器的報文進行處理,一般用來執行解碼、讀取客戶端數據、進行業務處理等;

ChannelOutboundHandler對從服務器發往客戶端的報文進行處理,一般用來進行編碼、發送報文到客戶端。

</blockquote>

ChannelPipeline

ChannelPipeline實際上應該叫做ChannelHandlerPipeline,可以把ChannelPipeline看成是一個ChandlerHandler的鏈表,當需要對Channel進行某種處理的時候,Pipeline負責依次調用每一個Handler進行處理。每個Channel都有一個屬于自己的Pipeline,調用Channel#pipeline()方法可以獲得Channel的Pipeline,調用Pipeline#channel()方法可以獲得Pipeline的Channel。

netty概述

ChannelPipeline的方法有很多,其中一部分是用來管理ChannelHandler的,如下面這些:

ChannelPipeline addFirst(String name, ChannelHandler handler);
ChannelPipeline addLast(String name, ChannelHandler handler);
ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler);
ChannelPipeline addAfter(String baseName, String name, ChannelHandler handler);
ChannelPipeline remove(ChannelHandler handler);
ChannelHandler remove(String name);
ChannelHandler removeFirst();
ChannelHandler removeLast();
ChannelPipeline replace(ChannelHandler oldHandler, String newName, ChannelHandler newHandler);
ChannelHandler replace(String oldName, String newName, ChannelHandler newHandler);
ChannelHandler first();
ChannelHandler last();
ChannelHandler get(String name);

ChannelHandlerContext

ChannelPipeline并不是直接管理ChannelHandler,而是通過ChannelHandlerContext來間接管理,這一點通過ChannelPipeline的默認實現DefaultChannelPipeline可以看出來。

netty概述

調用ChannelHandlerContext#channel()方法可以得到和Context綁定的Channel,調用ChannelHandlerContext#handler()方法可以得到和Context綁定的Handler。

ChannelPipeline和ChannelHandlerContext默認實現

DefaultChannelHandlerContext和DefaultChannelPipeline是ChannelHandlerContext和ChannelPipeline的默認實現,下面是它們的部分代碼:

final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {

    volatile DefaultChannelHandlerContext next;     volatile DefaultChannelHandlerContext prev;

    private final boolean inbound;     private final boolean outbound;     private final AbstractChannel channel;     private final DefaultChannelPipeline pipeline;     private final String name;     private final ChannelHandler handler;     private boolean removed;

    // ... }</pre>

final class DefaultChannelPipeline implements ChannelPipeline {
    // ...

    final DefaultChannelHandlerContext head;     final DefaultChannelHandlerContext tail;

    // ... }</pre>

從上面的代碼可以看出,在DefaultPipeline內部,DefaultChannelHandlerContext組成了一個雙向鏈表:

netty概述

再來看看DefaultChannelPipeline的構造函數:

    public DefaultChannelPipeline(AbstractChannel channel) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        this.channel = channel;

        TailHandler tailHandler = new TailHandler();         tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);

        HeadHandler headHandler = new HeadHandler(channel.unsafe());         head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);

        head.next = tail;         tail.prev = head;     }</pre>

可以看到,DefaultChinnelPipeline內部使用了兩個特殊的Handler來表示Handler鏈的頭和尾:

netty概述

ChannelHandler的種類

Netty中的所有handler都實現自ChannelHandler接口。按照輸出輸出來分,分為ChannelInboundHandler、ChannelOutboundHandler兩大類。ChannelInboundHandler對從客戶端發往服務器的報文進行處理,一般用來執行解碼、讀取客戶端數據、進行業務處理等;ChannelOutboundHandler對從服務器發往客戶端的報文進行處理,一般用來進行編碼、發送報文到客戶端。

從上面DefaultChannelHandlerContext代碼可以知道,Handler實際上分為兩種,Inbound和Outbound,這一點也可以從ChannelHandler接口的子接口得到證明:

public interface ChannelInboundHandler extends ChannelHandler {
  // ...
}

public interface ChannelOutboundHandler extends ChannelHandler {   // ... }</pre>


事件的傳播

為了搞清楚事件如何在Pipeline里傳播,讓我們從Channel的抽象子類AbstractChannel開始,下面是AbstractChannel#write()方法的實現:

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
    // ...
    @Override
    public Channel write(Object msg) {
        return pipeline.write(msg);
    }
    // ...
}

AbstractChannel直接調用了Pipeline的write()方法:

netty概述

final class DefaultChannelPipeline implements ChannelPipeline {
    // ...
    @Override
    public ChannelFuture write(Object msg) {
        return tail.write(msg);
    }
    // ...
}

因為write是個outbound事件,所以DefaultChannelPipeline直接找到tail部分的context,調用其write()方法:

netty概述

接著看DefaultChannelHandlerContext的write()方法:

final class DefaultChannelHandlerContext extends DefaultAttributeMap implements ChannelHandlerContext {
    // ...
    @Override
    public ChannelFuture write(Object msg) {
        return write(msg, newPromise());
    }

    @Override     public ChannelFuture write(final Object msg, final ChannelPromise promise) {         if (msg == null) {             throw new NullPointerException("msg");         }

        validatePromise(promise, true);

        write(msg, false, promise);

        return promise;     }

    private void write(Object msg, boolean flush, ChannelPromise promise) {         DefaultChannelHandlerContext next = findContextOutbound();         next.invokeWrite(msg, promise);         if (flush) {             next.invokeFlush();         }     }

    private DefaultChannelHandlerContext findContextOutbound() {         DefaultChannelHandlerContext ctx = this;         do {             ctx = ctx.prev;         } while (!ctx.outbound);         return ctx;     }

    private void invokeWrite(Object msg, ChannelPromise promise) {         try {             ((ChannelOutboundHandler) handler).write(this, msg, promise);         } catch (Throwable t) {             notifyOutboundHandlerException(t, promise);         }     }

    // ... }</pre>

context的write()方法沿著context鏈往前找,直至找到一個outbound類型的context為止,然后調用其invokeWrite()方法:

netty概述

invokeWrite()接著調用handler的write()方法:

netty概述

最后看看ChannelOutboundHandlerAdapter的write()方法實現:

public class ChannelOutboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelOutboundHandler {
    // ...
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ctx.write(msg, promise);
    }
    // ...
}

默認的實現調用了context的write()方法而不做任何處理,這樣write事件就沿著outbound鏈繼續傳播:

netty概述

可見,Pipeline的事件傳播,是靠Pipeline,Context和Handler共同協作完成的。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!