日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用

發布時間:2025/7/25 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Netty源碼分析第1章(Netty啟動流程)---->第4節: 注冊多路復用

?

Netty源碼分析第一章:Netty啟動流程

?

第四節:注冊多路復用

?

回顧下以上的小節, 我們知道了channel的的創建和初始化過程, 那么channel是如何注冊到selector中的呢?我們繼續分析

回到上一小節的代碼:

final ChannelFuture initAndRegister() {Channel channel = null;try {//創建channelchannel = channelFactory.newChannel();//初始化channel init(channel);} catch (Throwable t) {//忽略非關鍵代碼 }//注冊channelChannelFuture regFuture = config().group().register(channel);//忽略非關鍵代碼return regFuture; }

我們講完創建channel和初始化channel的關鍵步驟, 我們繼續跟注冊channel的步驟:

ChannelFuture regFuture = config().group().register(channel);

其中, 重點關注下register(channel)這個方法, 這個方法最終會調用到AbstractChannel中內部類AbstractUnsaferegister()方法, 具體如何調用到這個方法, 可以簡單帶大家捋一下

首先看下config()方法, 由于是ServerBootstrap調用的, 所以我們跟進去:

public final ServerBootstrapConfig config() {return config; }

返回的configServerBootrap的成員變量config:

private final ServerBootstrapConfig config = new ServerBootstrapConfig(this);

?

?

跟到ServerBootstrapConfig的構造方法:

ServerBootstrapConfig(ServerBootstrap bootstrap) {super(bootstrap); }

繼續跟到其父類AbstractBootstrapConfig的構造方法:

protected AbstractBootstrapConfig(B bootstrap) {this.bootstrap = ObjectUtil.checkNotNull(bootstrap, "bootstrap"); }

我們發現我們創建的ServerBootstrap作為參數初始化了其成員變量bootstrap

?

回到initAndRegister()方法:

config()返回的是ServerBootstrapConfig對象

再繼續跟到group()方法:

public final EventLoopGroup group() {return bootstrap.group(); }

這里調用Bootstrapgroup()方法:

public final EventLoopGroup group() {return group; }

這里返回了AbstractBootstrap的成員變量group, 我們回顧下第一小節, 還記得AbstractBootstrapgroup(EventLoopGroup group)方法嗎?

public B group(EventLoopGroup group) {this.group = group;return (B) this; }

group(EventLoopGroup group)方法初始化了我們boss線程, group()返回了boss線程, 也就是說?config().group().register(channel)?中的register()方法是boss線程對象調用的, 由于我們當初初始化的是NioEventLoopGroup, 因此走的是NioEventLoopGroup的父類的MultithreadEventLoopGroupregister()方法

跟到MultithreadEventLoopGroup的register()方法:

public ChannelFuture register(Channel channel) {return next().register(channel); }

這里的代碼看起來有點暈, 沒關系, 以后會講到, 現在可以大概做個了解, NioEventLoopGroup是個線程組, next()方法就是從線程組中選出一個線程, 也就是NioEventLoop線程, 所以這里的next()方法返回的是NioEventLoop對象, 其中register(channel)最終會調用NioEventLoop的父類SingleThreadEventLoopregister(channel)方法

跟到SingleThreadEventLoop的register(channel)方法:

public ChannelFuture register(Channel channel) {return register(new DefaultChannelPromise(channel, this)); }

其中DefaultChannelPromise類我們之后也會講到

?

我們先跟到register(new DefaultChannelPromise(channel, this)):

public ChannelFuture register(final ChannelPromise promise) {ObjectUtil.checkNotNull(promise, "promise");promise.channel().unsafe().register(this, promise);return promise; }

channel()會返回我們初始化的NioServerSocketChannel, unsafe()會返回我們創建channel的時候初始化的unsafe對象

跟進去看AbstractChannelunsafe()的實現:

public Unsafe unsafe() {return unsafe; }

這里返回的unsafe, 就是我們初始化channel創建的unsafe

回顧下第二小節channel初始化的步驟:

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

我們看unsafe的初始化:unsafe=newUnsafe()

?

跟到newUnsafe(), 我們之前講過NioServerSokectChannel的父類是AbstractNioMessageChannel, 所以會調用到到AbstractNioMessageChannel類中的newUnsafe()

跟到AbstractNioMessageChannel類中的newUnsafe():

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

我們看到這里創建了NioMessageUnsafe()對象, 所以在?promise.channel().unsafe().register(this, promise)?代碼中, unsafe()是返回的NioMessageUnsafe()對象, 最后調用其父類AbstractUnsafe(也就是AbstractChannel的內部類)register()方法,

?

簡單介紹下unsafe接口, unsafe顧名思義就是不安全的, 因為很多對channelio方法都定義在unsafe, 所以netty將其作為內部類進行封裝, 防止被外部直接調用, unsafe接口是Channel接口的內部接口, unsafe的子類也分別封裝在Channel的子類中, 比如我們現在剖析的register()方法, 就是封裝在AbstractChannel類的內部類AbstractUnsafe中的方法, 有關UnsafeChannel的繼承關系如下:

1-4-1

以上內容如果不明白沒有關系, 有關NioEventLoop相關會在后面的章節講到, 目前我們只是了解是如何走到AbstractUnsafe類的register()即可

?

我們繼續看看register()方法:

public final void register(EventLoop eventLoop, final ChannelPromise promise) {//代碼省略//所有的復制操作, 都交給eventLoop處理(1)AbstractChannel.this.eventLoop = eventLoop;if (eventLoop.inEventLoop()) {register0(promise);} else {try {eventLoop.execute(new Runnable() {@Overridepublic void run() {//做實際主注冊(2) register0(promise);}});} catch (Throwable t) {//代碼省略 }} }

我們跟著注釋的步驟繼續走, 第一步, 綁定eventLoop線程:

AbstractChannel.this.eventLoop = eventLoop;

eventLoopAbstractChannel的成員變量, 有關eventLoop, 我們會在緒章節講到, 這里我們只需要知道, 每個channel綁定唯一的eventLoop線程, eventLoop線程和channel的綁定關系就是在這里展現的

?

再看第二步, 做實際注冊:

我們先看if判斷, if(eventLoop.inEventLoop())

?

這里是判斷是不是eventLoop線程, 顯然我們現在是main()方法所在的線程, 所以走的else, eventLoop.execute()是開啟一個eventLoop線程, register0(promise)就是再開啟線程之后, 通過eventLoop線程執行的, 這里大家暫時作為了解

?

我們重點關注register0(promise), 跟進去:

private void register0(ChannelPromise promise) {try {//做實際的注冊(1) doRegister();neverRegistered = false;registered = true;//觸發事件(2) pipeline.invokeHandlerAddedIfNeeded();safeSetSuccess(promise);//觸發注冊成功事件(3) pipeline.fireChannelRegistered();if (isActive()) {if (firstRegistration) {//傳播active事件(4) pipeline.fireChannelActive();} else if (config().isAutoRead()) {beginRead();}}} catch (Throwable t) {//省略代碼 } }

我們重點關注doRegister()這個方法

?

doRegister()最終會調用AbstractNioChanneldoRegister()方法:

protected void doRegister() throws Exception {boolean selected = false;for (;;) {try {//jdk底層的注冊方法//第一個參數為selector, 第二個參數表示不關心任何事件selectionKey = javaChannel().register(eventLoop().selector, 0, this);return;} catch (CancelledKeyException e) {//省略代碼 }} }

我們終于看到和java底層相關的方法了

跟到javaChannel()的方法中:

protected SelectableChannel javaChannel() {return ch; }

這個ch, 就是本章第二小節創建NioServerSocketChannel中初始化的jdk底層ServerSocketChannel

這里register(eventLoop().selector, 0, this)方法中eventLoop().selector, 是獲得每一個eventLoop綁定的唯一的selector, 0代表這次只是注冊, 并不監聽任何事件, this是代表將自身(NioEventLoopChannel)作為屬性綁定在返回的selectionKey當中, 這個selectionKey就是與每個channel綁定的jdk底層的SelectionKey對象, 熟悉nio的小伙伴應該不會陌生, 這里不再贅述

?

回到register0(ChannelPromise promise)方法, 我們看后續步驟:

步驟(2)是觸發handler的需要添加事件, 事件傳遞的內容我們將在后續課程詳細介紹, 這里不必深究

步驟(3)是觸發注冊成功事件(3), 同上

步驟(4)是傳播active事件(4), 這里簡單強調一下, 這里的方法pipeline.fireChannelActive()第一個注冊是執行不到的, 因為isActive()會返回false, 因為鏈路沒完成

本小節梳理了有注冊多路復用的相關邏輯, 同學們可以跟著代碼自己走一遍以加深印象

?

上一節: 服務端Channel的初始化

下一節: 綁定端口

?

posted on 2018-12-31 18:11 向南是個萬人迷 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/xiangnan6122/p/10202849.html

總結

以上是生活随笔為你收集整理的Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 视频在线观看你懂的 | 伊人色网 | 久久久久网站 | 国产三级理论 | 国产在线一级片 | 人人插人人干 | 久久咪咪 | 青青草国产成人av片免费 | 九色蝌蚪视频 | 热久久久久久久 | 99久久精 | 日韩大片一区二区 | 天堂av影院 | 欧美一级片网址 | 4438全国最大成人网 | 国产 丝袜 欧美中文 另类 | 国产一区二区三区免费观看视频 | 激情小说视频在线 | 国产乱码精品一区二三赶尸艳谈 | 天堂一区二区三区 | 无码一区二区三区免费 | 亚洲狼人综合网 | 污视频网址在线观看 | 穿情趣内衣被c到高潮视频 欧美性猛交xxxx黑人猛交 | 日韩在线观看网址 | 男女做那个的全过程 | 国产福利在线视频观看 | 欧美第一页在线观看 | 免费搞黄网站 | 粗大的内捧猛烈进出在线视频 | 中文字幕乱码免费 | 男人日女人免费视频 | 热久久中文字幕 | 中文字幕91 | 牲欲强的熟妇农村老妇女视频 | 无码av免费精品一区二区三区 | 青青草成人影视 | 怡红院最新网址 | 欧美成人久久久 | av成人免费 | 91麻豆精品国产91久久久久久久久 | 伊人精品国产 | brazzers精品成人一区 | 欧美日韩高清免费 | 男人综合网 | 一二三在线视频 | 久久免费播放视频 | 午夜激情电影在线观看 | 中文字幕日韩一区 | 日韩精品网站 | 久久综合中文字幕 | 久久com | 在线观看一区二区三区四区 | 欧美真人性野外做爰 | a在线v| 国产精品一区二区三区免费看 | 99久久久无码国产精品免费蜜柚 | 在线观看一区视频 | 亚洲免费二区 | www一区| 日韩一区精品 | 老女人性视频 | 男人天堂电影 | 国产综合在线播放 | 成人网一区 | 国模视频一区二区 | 欧美日本中文字幕 | av.www| 亚洲男人网 | 欧美亚洲在线观看 | 肉肉av福利一精品导航 | 99国产精品| 成年人网站黄 | 欧美丰满美乳xxx高潮www | 日韩精品手机在线 | 久久久97| 色屁屁一区二区三区视频 | 精品国产91久久久久久 | 欧美aaa在线观看 | 制服诱惑一区二区三区 | 奇米狠狠 | 欧美 日韩 国产 中文 | 99久久婷婷 | 日本黄色成人 | 色窝在线 | 成人无码av片在线观看 | 日韩成人午夜电影 | 国产色啪 | 日韩一区电影 | 亚洲少妇自拍 | 宅男视频在线免费观看 | 永久在线 | 国产精品久久久久久久久 | 国产一级片a | 狠狠干综合网 | 国产激情网站 | 最新av网站在线观看 | 制服丝袜av一区二区三区下载 | 成人高潮片免费视频 |