成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Netty4.x 源碼實戰(zhàn)系列(三):NioServerSocketChannel全剖析

Flink_China / 764人閱讀

摘要:本篇將通過實例化過程,來深入剖析。及初始化完成后,它們會相互連接。我們在回到的構(gòu)造方法父類構(gòu)造方法調(diào)用完成后,還要初始化一下自己的配置對象是的內(nèi)部類而又是繼承自,通過代碼分析,此對象就是就會對底層一些配置設(shè)置行為的封裝。

根據(jù)上一篇《Netty4.x 源碼實戰(zhàn)系列(二):服務(wù)端bind流程詳解》所述,在進行服務(wù)端開發(fā)時,必須通過ServerBootstrap引導類的channel方法來指定channel類型, channel方法的調(diào)用其實就是實例化了一個用于生成此channel類型對象的工廠對象。 并且在bind調(diào)用后,會調(diào)用此工廠對象來生成一個新channel。

本篇將通過NioServerSocketChannel實例化過程,來深入剖析NioServerSocketChannel。

在開始代碼分析之前,我們先看一下NioServerSocketChannel的類繼承結(jié)構(gòu)圖:

調(diào)用工廠完成NioServerSocketChannel實例的創(chuàng)建

在綁定偵聽端口過程中,我們調(diào)用了AbstractBootstrap的initAndRegister方法來完成channel的創(chuàng)建與初始化,channel實例化代碼如下:

channelFactory.newChannel()

而channelFactory對象是我們通過ServerBootstrap.channel方法的調(diào)用生成的

 public B channel(Class channelClass) {
    if (channelClass == null) {
        throw new NullPointerException("channelClass");
    }
    return channelFactory(new ReflectiveChannelFactory(channelClass));
}

通過代碼可知,此工廠對象是ReflectiveChannelFactory實例

public class ReflectiveChannelFactory implements ChannelFactory {

    private final Class clazz;

    public ReflectiveChannelFactory(Class clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz");
        }
        this.clazz = clazz;
    }

    @Override
    public T newChannel() {
        try {
            return clazz.getConstructor().newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }
}

所以 channelFactory.newChannel() 實例化其實就是NioServerSocketChannel無參構(gòu)造方法反射而成。

NioServerSocketChannel實例化過程分析

我們先看一下NioServerSocketChannel的無參構(gòu)造代碼

public NioServerSocketChannel() {
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

無參構(gòu)造方法中有兩個關(guān)鍵點:
1、使用默認的多路復用器輔助類 DEFAULT_SELECTOR_PROVIDER

 private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

2、通過newSocket創(chuàng)建ServerSocketChannel

private static ServerSocketChannel newSocket(SelectorProvider provider) {
    try {
       
        return provider.openServerSocketChannel();
    } catch (IOException e) {
        throw new ChannelException(
                "Failed to open a server socket.", e);
    }
}

我們將newSocket生成的ServerSocketChannel對象繼續(xù)傳遞給本類中的NioServerSocketChannel(ServerSocketChannel channel)構(gòu)造方法

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

在其內(nèi)部,我們會調(diào)用父類AbstractNioMessageChannel的構(gòu)造方法:

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

因為是服務(wù)端新生成的channel,第一個參數(shù)指定為null,表示沒有父channel,第二個參數(shù)指定為ServerSocketChannel,第三個參數(shù)指定ServerSocketChannel關(guān)心的事件類型為SelectionKey.OP_ACCEPT。

在AbstractNioMessageChannel內(nèi)部會繼續(xù)調(diào)用父類AbstractNioChannel的構(gòu)造方法:

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    // 繼續(xù)調(diào)用父類構(gòu)造方法
    super(parent);
    // 將ServerSocketChannel對象保存
    this.ch = ch;
    // 設(shè)置關(guān)心的事件
    this.readInterestOp = readInterestOp;
    try {
        // 設(shè)置當前通道為非阻塞的
        ch.configureBlocking(false);
    } catch (IOException e) {
        try {
            ch.close();
        } catch (IOException e2) {
            if (logger.isWarnEnabled()) {
                logger.warn(
                        "Failed to close a partially initialized socket.", e2);
            }
        }

        throw new ChannelException("Failed to enter non-blocking mode.", e);
    }
}

在AbstractNioChannel中做了下面幾件事:
1、繼續(xù)調(diào)用父類AbstractChannel(Channel parent)構(gòu)造方法;
2、通過this.ch = ch 保存ServerSocketChannel, 因為NioServerSocketChannel是Netty封裝的對象,而ServerSocketChannel是有前面默認selector_provider生成的,是java nio的, 其實“this.ch = ch”可以被認為是綁定java nio服務(wù)端通道至netty對象中;
3、設(shè)置ServerSocketChannel關(guān)心的事件類型;
4、設(shè)置ServerSocketChannel為非阻塞的(熟悉Java NIO的都知道如果不設(shè)置為false,啟動多路復用器會報異常)

我們再看一下AbstractChannel(Channel parent)的內(nèi)部代碼細節(jié)

protected AbstractChannel(Channel parent) {
    this.parent = parent;
    id = newId();
    unsafe = newUnsafe();
    pipeline = newChannelPipeline();
}

此構(gòu)造方法中,主要做了三件事:
1、給channel生成一個新的id
2、通過newUnsafe初始化channel的unsafe屬性
3、newChannelPipeline初始化channel的pipeline屬性

id的生成我們就不細究了,我們主要看看newUnsafe 及 newChannelPipeline是如何創(chuàng)建unsafe對象及pipeline對象的。

newUnsafe()方法調(diào)用
在AbstractChannel類中,newUnsafe()是一個抽象方法

protected abstract AbstractUnsafe newUnsafe();

通過上面的類繼承結(jié)構(gòu)圖,我們找到AbstractNioMessageChannel類中有newUnsafe()的實現(xiàn)

@Override
protected AbstractNioUnsafe newUnsafe() {
    return new NioMessageUnsafe();
}

此方法返回一個NioMessageUnsafe實例對象,而NioMessageUnsafe是AbstractNioMessageChannel的內(nèi)部類

private final class NioMessageUnsafe extends AbstractNioUnsafe {

    private final List readBuf = new ArrayList();

    @Override
    public void read() {
        assert eventLoop().inEventLoop();
        final ChannelConfig config = config();
        final ChannelPipeline pipeline = pipeline();
        final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
        allocHandle.reset(config);

        boolean closed = false;
        Throwable exception = null;
        try {
            try {
                do {
                    int localRead = doReadMessages(readBuf);
                    if (localRead == 0) {
                        break;
                    }
                    if (localRead < 0) {
                        closed = true;
                        break;
                    }

                    allocHandle.incMessagesRead(localRead);
                } while (allocHandle.continueReading());
            } catch (Throwable t) {
                exception = t;
            }

            int size = readBuf.size();
            for (int i = 0; i < size; i ++) {
                readPending = false;
                pipeline.fireChannelRead(readBuf.get(i));
            }
            readBuf.clear();
            allocHandle.readComplete();
            pipeline.fireChannelReadComplete();

            if (exception != null) {
                closed = closeOnReadError(exception);

                pipeline.fireExceptionCaught(exception);
            }

            if (closed) {
                inputShutdown = true;
                if (isOpen()) {
                    close(voidPromise());
                }
            }
        } finally {
            if (!readPending && !config.isAutoRead()) {
                removeReadOp();
            }
        }
    }
}

NioMessageUnsafe 只覆蓋了 父類AbstractNioUnsafe中的read方法,通過NioMessageUnsafe 及其父類的代碼便可以知道, 其實unsafe對象是真正的負責底層channel的連接/讀/寫等操作的,unsafe就好比一個底層channel操作的代理對象。

newChannelPipeline()方法調(diào)用
newChannelPipeline直接在AbstractChannel內(nèi)實現(xiàn)

protected DefaultChannelPipeline newChannelPipeline() {
    return new DefaultChannelPipeline(this);
}

該方法返回了創(chuàng)建了一個DefaultChannelPipeline對象

protected DefaultChannelPipeline(Channel channel) {
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    succeededFuture = new SucceededChannelFuture(channel, null);
    voidPromise =  new VoidChannelPromise(channel, true);

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

    head.next = tail;
    tail.prev = head;
}

此DefaultChannelPipeline對象會綁定NioServerSocketChannel對象,并初始化了HeadContext及TailContext對象。

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

head及tail初始化完成后,它們會相互連接。

通過上面的代碼可以得出,pipeline就是一個雙向鏈表。關(guān)于Pipeline的更多細節(jié),此處不做贅述,歡迎大家關(guān)注下一篇文章。

我們在回到NioServerSocketChannel的構(gòu)造方法 NioServerSocketChannel(ServerSocketChannel channel)

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

父類構(gòu)造方法調(diào)用完成后,NioServerSocketChannel還要初始化一下自己的配置對象

config = new NioServerSocketChannelConfig(this, javaChannel().socket());

NioServerSocketChannelConfig是NioServerSocketChannel的內(nèi)部類

private final class NioServerSocketChannelConfig extends DefaultServerSocketChannelConfig {
    private NioServerSocketChannelConfig(NioServerSocketChannel channel, ServerSocket javaSocket) {
        super(channel, javaSocket);
    }

    @Override
    protected void autoReadCleared() {
        clearReadPending();
    }
}

而NioServerSocketChannelConfig 又是繼承自DefaultServerSocketChannelConfig,通過代碼分析,此config對象就是就會對底層ServerSocket一些配置設(shè)置行為的封裝。

至此NioServerSocketChannel對象應(yīng)該創(chuàng)建完成了~

總結(jié):

1、NioServerSocketChannel對象內(nèi)部綁定了Java NIO創(chuàng)建的ServerSocketChannel對象;

2、Netty中,每個channel都有一個unsafe對象,此對象封裝了Java NIO底層channel的操作細節(jié);

3、Netty中,每個channel都有一個pipeline對象,此對象就是一個雙向鏈表;

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68104.html

相關(guān)文章

  • Netty4.x 源碼實戰(zhàn)系列(二):服務(wù)端bind流程詳解

    摘要:對于,目前大家只知道是個線程組,其內(nèi)部到底如何實現(xiàn)的,它的作用到底是什么,大家也都不太清楚,由于篇幅原因,這里不作詳細介紹,后面會有文章作專門詳解。 在上一篇《ServerBootstrap 與 Bootstrap 初探》中,我們已經(jīng)初步的了解了ServerBootstrap是netty進行服務(wù)端開發(fā)的引導類。 且在上一篇的服務(wù)端示例中,我們也看到了,在使用netty進行網(wǎng)絡(luò)編程時,我...

    laoLiueizo 評論0 收藏0
  • Netty4.x 源碼實戰(zhàn)系列(四):Pipeline剖析

    摘要:在上一篇源碼實戰(zhàn)系列三全剖析中,我們詳細分析了的初始化過程,并得出了如下結(jié)論在中,每一個都有一個對象,并且其內(nèi)部本質(zhì)上就是一個雙向鏈表本篇我們將深入源碼內(nèi)部,對其一探究竟,給大家一個全方位解析。 在上一篇《Netty4.x 源碼實戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們詳細分析了NioServerSocketChannel的初始化過程,并得出了如下結(jié)論...

    13651657101 評論0 收藏0
  • Netty4.x 源碼實戰(zhàn)系列(一):ServerBootstrap 與 Bootstrap 初探

    摘要:而用于主線程池的屬性都定義在中本篇只是簡單介紹了一下引導類的配置屬性,下一篇我將詳細介紹服務(wù)端引導類的過程分析。 從Java1.4開始, Java引入了non-blocking IO,簡稱NIO。NIO與傳統(tǒng)socket最大的不同就是引入了Channel和多路復用selector的概念。傳統(tǒng)的socket是基于stream的,它是單向的,有InputStream表示read和Outpu...

    BakerJ 評論0 收藏0
  • 【自己讀源碼Netty4.X系列(二) 啟動類成員Channel

    摘要:下面無恥的貼點源碼。啟動類我們也學,把啟動類抽象成兩層,方便以后寫客戶端。別著急,我們慢慢來,下一篇我們會了解以及他的成員,然后,完善我們的程序,增加其接收數(shù)據(jù)的能力。文章的源碼我會同步更新到我的上,歡迎大家,哈哈。 廢話兩句 這次更新拖了很長時間,第一是自己生病了,第二是因為最開始這篇想寫的很大,然后構(gòu)思了很久,發(fā)現(xiàn)不太合適把很多東西寫在一起,所以做了點拆分,準備國慶前完成這篇博客。...

    waterc 評論0 收藏0
  • Netty4.x 源碼實戰(zhàn)系列(五):深入淺出學NioEventLoopGroup

    摘要:接下來的兩篇文章,我將從源碼角度為大家深入淺出的剖析的線程模型工作機制。我們看一下的源碼通過的代碼發(fā)現(xiàn),實現(xiàn)了接口,其內(nèi)部會通過指定的默認線程工廠來創(chuàng)建線程,并執(zhí)行相應(yīng)的任務(wù)。至此,初始化完成了。下一篇我們將詳細介紹,敬請期待。 我們都知道Netty的線程模型是基于React的線程模型,并且我們都知道Netty是一個高性能的NIO框架,那么其線程模型必定是它的重要貢獻之一。 在使用ne...

    MSchumi 評論0 收藏0

發(fā)表評論

0條評論

Flink_China

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<