1. 程式人生 > >Netty原始碼分析:1.3初始化NioServerSocketChannel

Netty原始碼分析:1.3初始化NioServerSocketChannel

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有:
|———1.1初始化NioEventLoopGroup
|———1.2初始化NioEventLoop
|———1.3初始化NioServerSocketChannel
|———1.4伺服器啟動流程
為什麼先從初始化開始瞭解伺服器啟動?
因為在我看伺服器啟動的相關原始碼的時候,有很多地方都是初始化的時候已經建立好的。所以我就從初始化的原始碼開始看起。這是我第一次看原始碼的筆記,仍有很多理解錯誤的地方和不解的地方。歡迎討論。

本篇目錄:

  • 類的繼承關係圖
  • 時序圖
  • 程式碼分析
  • 疑問

類的繼承關係圖

image.png

時序圖

image.png

NioServerSocketChannel的構造器

super(null, channel, SelectionKey.OP_ACCEPT);
第一個引數是Channel類
第二個引數是SelectableChannel
第三個引數是int:SelectionKey.OP_ACCEPT 讓我想起了NIO中給一個channel繫結一個selector管理器。

public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new
NioServerSocketChannelConfig(this, javaChannel().socket()); }

初始化開始

1. DefaultAttributeMap

首先是從DefaultAttributeMap開始初始化
該類實現了AttributeMap介面,主要是更加降低損耗。

2. AbstractChannel

  • parent 屬性為null: 從NioServerSocketChannel的構造器可以知道第一個引數Channel 是null。
  • unsafe:新建一個NioMessageUnsafe
  • pipeline:新建一個Pipeline。也就是說一個channel一個Pipeline.
    netty對底層socket的操作都是通過unsafe來做的。unsafe主要由兩種不同的實現NioMessageUnsafe和NioByteUnsafe.NioMessageUnsafe是服務端的。
protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }

3. AbstractNioChannel

  • 1 初始化AbstractChannel
  • 2 ch的型別是SelectableChannel。就是相當於儲存該selector管理器
  • 3 儲存Int ,也就是初始化SelectionKey.OP_ACCEPT 感興趣事件。
  • 4 設定非阻塞模式。相當於nio裡設定channel非阻塞。
 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent); //1
        this.ch = ch;  //2 
        this.readInterestOp = readInterestOp; //3
        try {
            ch.configureBlocking(false); //4
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {                
            }
        }
    }

4. AbstractNioMessageChannel

protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent, ch, readInterestOp);
    }

5. NioServerSocketChannel

  • 1 對Channel進行配置。與ChannelOption類類似。
public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket()); //1
    }

這樣一個NioServerSocketChannel的物件就已經建立完成了。

總結

整個NioServerSocketChannel的初始化,我覺得就是建立一個channel物件,在該物件裡面附帶一些屬性,這些屬性有:
- unsafe:NioMessageUnsafe
- pipeline管道。
- SelectableChannel並將該Channel設定為非阻塞
- 附帶一個感興趣事件:OP_ACCEPT
- 設定預設的Channel配置。

疑問

unsafe 是什麼?

nterface Unsafe {
    SocketAddress localAddress();
    SocketAddress remoteAddress();
    void register(EventLoop eventLoop, ChannelPromise promise);
    void bind(SocketAddress localAddress, ChannelPromise promise);
    void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
    void disconnect(ChannelPromise promise);
    void close(ChannelPromise promise);
    void closeForcibly();
    void deregister(ChannelPromise promise);
    void beginRead();
    void write(Object msg, ChannelPromise promise);
    void flush();
    ChannelPromise voidPromise();
    ChannelOutboundBuffer outboundBuffer();
}

可以看出,這些方法都是java底層的Socket的操作。
所以回到底層操作,都是需要用到這些方法。

pipeline 的初始化到底做了什麼?

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

    tail = new TailContext(this);
    head = new HeadContext(this);

    head.next = tail;
    tail.prev = head;
}
  • 首先是Pipeline與channel繫結在一次。也就是Pipeline裡有和channel的引數,用來儲存該例項。
  • headtail是雙向連結串列的頭和尾。因為Pipeline是一個雙向連結串列。此時頭和尾都是指向自己。