婷婷五色,五月天激情婷婷大综合,亚洲综合久久久久久中文字幕,国产ww久久久久久久久久,婷婷综合缴情亚洲五月伊,欧美日韩不卡在线

首頁 > 生活 >

【Netty源碼分析】04 服務端讀流程

讀流程

客戶端接入后,下面一步操作就是讀取客戶端傳輸過來的數據,這一節我們就來分析下服務端讀取客戶端數據流程。從前面分析來看,channel的事件輪詢、事件處理是在NioEventLooprun方法中,從這里我們就很容易找我服務端讀流程的入口方法:processSelectedKeys()


(資料圖片)

processSelectedKeys()一直追蹤下去,可以看到OP_READ處理邏輯分支:

if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { unsafe.read();}

可能你會比較奇怪:為什么OP_READOP_ACCEPT都會走這個分支?

OP_ACCEPTNioServerSocketChannel處理的事件,而OP_READNioSocketChannel處理的事件,所以,雖然它們都走這個分支,但是channel類型確是不一樣的,即這里的unsafe類型也不一樣,一個是:NioMessageUnsafe,另一個是:NioSocketChannelUnsafeNioServerSocketChannel負責監聽客戶端連接,當有客戶端連接進入時,對它來說就是有個讀入消息需要被處理。

這里我們是處理client channleOP_READ,所以,unsafeNioSocketChannelUnsafe類型實例。

AbstractNioByteChannel.NioByteUnsafe#read方法代碼如下:

public final void read() { final ChannelConfig config = config();    if (shouldBreakReadReady(config)) {     clearReadPending();         return;    }    final ChannelPipeline pipeline = pipeline();    final ByteBufAllocator allocator = config.getAllocator();    final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();    allocHandle.reset(config);    ByteBuf byteBuf = null;    boolean close = false;    try {        do {            // 申請ByteBuf對象            byteBuf = allocHandle.allocate(allocator);            //doReadBytes(byteBuf):將數據讀取到ByteBuf中            //lastBytesRead()將讀取的字節數設置到lastBytesRead            allocHandle.lastBytesRead(doReadBytes(byteBuf));            if (allocHandle.lastBytesRead() <= 0) {                byteBuf.release();                byteBuf = null;                close = allocHandle.lastBytesRead() < 0;                if (close) {                    readPending = false;                }                break;            }            allocHandle.incMessagesRead(1);            readPending = false;            //觸發pipeline channelRead事件,將讀入數據ByteBuf傳入到handler中            pipeline.fireChannelRead(byteBuf);            byteBuf = null;        } while (allocHandle.continueReading());//判斷是否繼續讀取          allocHandle.readComplete();        //觸發pipeline channelReadComplete        pipeline.fireChannelReadComplete();        if (close) {            closeOnRead(pipeline);        }    } catch (Throwable t) {        handleReadException(pipeline, byteBuf, t, close, allocHandle);    } finally {        if (!readPending && !config.isAutoRead()) {            removeReadOp();        }    }}

這個方法刨除其它邏輯,關于客戶端數據處理邏輯主要包括3個步驟:

allocHandle.lastBytesRead(doReadBytes(byteBuf)):調用java api,從channel中讀取字節數據到ByteBuf緩存中;pipeline.fireChannelRead(byteBuf):觸發pipelinechannelRead事件,并將帶有讀入數據的ByteBuf通過參數傳入;pipeline.fireChannelReadComplete():觸發pipelinechannelReadComplete事件;

事件傳播

調用pipelinefireChannelRead()就可觸發channelRead事件在handler之間傳播,事件傳播這塊代碼比較繞,給人感覺不停的來回調用容易繞暈,下面通過圖可以更加直觀的看出調用流程,再配合代碼就很好理解了。

關鍵點就在于HandlerContext中提供了一個靜態方法:invokeChannelRead(final AbstractChannelHandlerContext next, Object msg),第一個是在哪個handler上觸發事件,第二個參數就是數據本身,通過這個方法就可以指定在哪個handler上觸發channelRead事件。由于pipeline中的handler是被包裝成HandlerContext放入的,所以,可以通過handler()方法找到真正的handler對象進行觸發。

比如pipelinefireChannelRead()就是觸發headchannelRead事件,如果處理完成需要把事件繼續傳播給下一個handler,就需要調用ctx.fireChannelRead(msg)方法即可,該方法中通過next屬性獲取到下一個節點,然后執行static invokeChannelRead(next, msg)這個方法就可以將事件傳播到下一個節點上。

pipeline.fireChannelRead(byteBuf)運行完成后會調用pipeline.fireChannelReadComplete()方法,觸發channelReadComplete事件,執行機制和channelRead事件一樣,就不再贅述。

搞清楚上面原理,就很容易理解ctx.fireChannelRead()ctx.pipeline().fireChannelRead()之間的區別了,避免誤用。

Pipeline線程模型

上面分析的都是常規模式,沒有給handler指定額外線程情況下channelReadchannelReadComplete傳播機制,大致如下圖:

先觸發channelRead事件,按照pipeline中順序依次觸發,當所有handler都觸發完后,再觸發channelReadComplete事件,按照pipeline中的順序依次觸發。這些所有流程采用的都是同步方式,在同一個線程中執行,這個線程就是channel注冊的NioEventLoop

我們來看下static void invokeChannelRead()這個方法:

static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {    final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);    EventExecutor executor = next.executor();    if (executor.inEventLoop()) {        next.invokeChannelRead(m);    } else {        executor.execute(new Runnable() {            @Override            public void run() {                next.invokeChannelRead(m);            }        });    }}

在執行next.invokeChannelRead(m)方法前有個executor.inEventLoop()判斷,判斷當前執行線程是不是就是handler執行所需的線程。執行handler方法是不能隨便線程都可以去執行的,必須使用handler內部指定的executor線程執行器中執行才行。如下圖,也就是說紅色框框中的內容必須在executor線程執行器中執行,如果當前線程和handler執行線程不是同一個,就需要進行線程切換:則調用封裝成一個任務,提交到executor的任務隊列中讓其執行。

executor線程執行器是通過next.executor()方法獲取到的,從這個方法源碼中可以看到獲取邏輯:如果HandlerContextexecutor有值則直接返回;否則返回channel注冊的NioEventLoop作為線程執行器。

在添加handler時可以指定一個EventGrouppipeline.addLast( bizGroup, "handler2", new OtherTest02());,這樣,再把handler包裝成HandlerContext過程中會從這個EventGroup根據chooser選取策略獲得一個EventLoop賦值給executor

所以,從上面分析,默認情況下handler都是在channel注冊的NioEventLoop線程中執行的,除非在addLast添加handloer時特別指定。

下面我們通過一個案例分析下pipeline線程模型,如下,給handler02添加一個額外的線程池:

EventLoopGroup bizGroup = new NioEventLoopGroup(10, new ThreadFactoryBuilder().setNameFormat("biz-%s").build());protected void initChannel(SocketChannel ch) throws Exception {    ChannelPipeline pipeline = ch.pipeline();    pipeline.addLast( "handler01", new OtherTest01());    pipeline.addLast( bizGroup, "handler02", new OtherTest02());    pipeline.addLast( "handler03", new OtherTest03());}

這時,channelReadchannelReadComplete事件觸發流程見下圖:

channelRead事件執行流程說明:

上下兩部分代表兩個線程,上面是channel注冊的eventLoop,下面是添加handler02指定的eventLoop;首先觸發handler01channelRead事件,本身當前線程和handler01是同一個線程,所以,直接調用handler#channelRead()方法;handler01#channelRead()方法執行完成后,事件繼續向下傳播,需要調用handler02#channelRead()方法,但是handler02執行線程并不是默認的channel的注冊線程,而是額外設置的biz線程,需要將調用包裝成一個任務提交到biz線程的任務隊列taskQueue中,然后直接返回;biz線程執行器內部線程會一直循環從taskQueue中獲取任務執行,這樣就完成了線程切換效果;當handler02#channelRead()方法執行完成后,需要執行handler03#channelRead(),它們又不在同一個線程中執行,這時有需要切換線程,所以會把handler03#channelRead()的調用封裝成一個任務提交到register eventLoop的taskQueue中,待其內部線程提取執行;

下面再來看下channelReadComplete事件執行流程:

上圖a1將任務提交給taskQueue任務隊列后直接返回了,而不是等其執行完成再返回;a1返回后,從源碼分析來看,會立即觸發channelReadComplete事件,涉及到線程切換,同理b1這里也是將handler02#channelReadComplete()調用封裝成任務放入到biz eventLooptaskQueue中的,然后也直接返回了;這樣,biz eventLoop線程執行器taskQueue中就有兩個任務,會按照順序依次執行:先執行channelRead()調用,再執行channelReadComplete()調用;執行a3、b3時同理;

總結

從上面可以看出,Pipelinehandler可以在不同線程間切換得到關鍵是:taskQueue。還要一點非常重要:handler線程池執行器默認使用的channel注冊的NioEventLoop這個,NioEventLoop采用的是單線程工作模式,同時還需要處理selector.select()事件輪詢,所以,handler里肯定不能有耗時、特別是IO阻塞等操作,不然卡在handler中,selector#select()執行不到,無法及時接收到客戶端傳送過來的數據。

關鍵詞:

責任編輯:Rex_29

推薦閱讀

當前速看:強國必先強農

· 2023-03-28 19:34:52

關于我們 聯系我們 商務合作 誠聘英才 網站地圖

Copyright @ 2008-2020 www.miyueyun.com.cn Corporation,All Rights Reserved

熱訊新聞網 版權所有 備案號:豫ICP備20005723號-6
文章投訴郵箱:2 9 5 9 1 1 5 7 8@qq.com 違法信息舉報郵箱:jubao@123777.net.cn

營業執照公示信息

国产爆乳无码福利电影| 国产成人久久AV免费看| 亚洲国产精品成人精品无码区| 女儿儿媳陪自己玩的心情说说| 国产精品久久久久久亚洲影视| 在线精品自偷自拍无码中文| 天天躁日日躁很很躁2022| 老阿姨哔哩哔哩B站肉片入口6 | 男生晚上睡不着想看B站| 国产成人午夜福利不卡在线观看| 有人有在线观看的片资源| 天天澡天天揉揉AV无码| 美女喷水一区国产| 国产偷国产偷亚洲高清日韩| AV免费啪啪永久| 亚洲国产成人AⅤ毛片奶水| 日本三线和韩国三线的市场定位| 久久99精品久久久久久青青| 嗯…啊 摸 湿 奶头免费视频| 亚洲综合日韩AV无码毛片| 天堂中文在线最新版地址| 免费拗女网站1300部| 国产亚洲无线码一区二区| JAPAN丰满人妻HDXXXX| 亚洲精品无码AV专区最新| 色婷婷亚洲一区二区综合| 久久综合狠狠综合久久| 国产农村妇女毛片精品久久麻豆| BGMBGMBGM老太太XX一| 亚洲第一无码AV播放器| 色窝窝无码一区二区三区色欲| 麻豆传煤入口免费进入2023| 国产同性GV男男在线观看| X姓女RAPPER的首次亮相| 亚洲欧美另类视频| 天堂√最新版中文在线地址| 拧花蒂尿用力按凸起喷水尿视频| 国偷自产AⅤ一区二区三区| 成人无码AⅤ久久精品国产传媒| 一本一道波多野结衣一区| 午夜亚洲AⅤ无码高潮片在线观看| 欧美日韩中文国产一区| 久久精品国产亚洲AV麻豆王友容| 国产黄在线观看免费观看不卡| CHINESE交换俱乐部4P| 亚洲色欲色欲WWW成人网| 我和岳乱妇三级高清电影| 欧美性激烈粗大精品XXX| 久久精品无码一区二区软件| 国产精品亚洲污污网站入口| 白嫩的18SEX少妇HD| 中国少妇的BBWWBBWW| 亚洲AV永久无码成人红楼影视| 揉着我的奶从后面进去| 嫩草在线视频WWW免费看| 精东传媒VS天美传媒电影| 国产成人无码AV在线播放DVD| FREE国产粉嫩熟妇XXXHD| 夜夜精品浪潮AV一区二区三区| 亚洲 都市 无码 校园 激情| 色8激情欧美成人久久综合电| 内射中出日韩无国产剧情| 精品一区二区三区自拍图片区| 国产精品成人99久久久久 | 被农民工玩酥的黄小婷| 越南少妇BBV叉叉叉| 亚洲国产精品久久艾草纯爱| 无码国产精品一区二区免费模式 | 日本巨大的奶头在线观看| 麻花传媒剧国产MV入口在线观看| 后入骚妇内射AV| 国产精品国产精品国产专区不卡 | 日本又黄又爽又色又刺激的视频| 男女猛烈无遮挡免费视频| 久久精品AⅤ无码中文字字幕蜜桃 久久精品AⅤ无码中文字字幕 | 成人无码H动漫在线播放| 3D动漫精品啪啪一区二区免费| 亚洲欭美日韩颜射在线| 亚洲AV无码一区二区三区蜜桃| 四川丰满少妇被弄到高潮| 日99久9在线 | 免费| 男人激烈吮乳吃奶动态图| 久久久久久久久毛片精品| 含羞草传媒每天免费三次看剧| 国产成人免费ā片在线观看老同学| 啊灬啊灬啊灬快高潮了网站| 2021国产麻豆剧传媒在线| 夜夜爽妓女77777免费观看| 亚洲国产精品无码7777一线| 小妖精太湿太紧了拔不出| 天天爽天天狠久久久综合麻豆| 日韩欧群交P片内射中文 | 男人放进女人里面叫什么| 久无码久无码AV无码| 精品午夜福利在线观看| 黑人与人妻无码中字视频| 国产日韩精品SUV| 国产成人综合亚洲AV| 公的大龟慢慢挺进我的体内| 插插插精品亚洲一区| JULIA无码中文字幕一区| 91人人妻人人澡人人爽超污| 在床上拔萝卜又疼又叫什么症状| 亚洲愉拍99热成人精品热久久| 亚洲国产精品无码久久久| 亚洲va熟妇自拍无码区| 亚州日本乱码一区二区三区| 无码人妻在线视频| 无码H肉男男在线观看免费| 他一边曰一边吃我奶小说免看| 色欲AV无码中字乱人伦在线| 日产乱码一二三区别免费下| 人与性动交AAAABBBB| 日本丰满少妇精品| 日本黑人乱偷人妻中文字幕| 人妻穿丁字裤陪客户| 人妻丰满熟妇无码AV| 人妻JapanXXXX精品HD| 人妻 丝袜美腿 中文字幕| 欧美性猛交╳XXX乱大交| 欧美在线视频一区二区| 欧美人与人动人物2020| 欧美熟妇精品一区二区蜜桃视频 | 免费无码成人AV片在线在线播放| 麻花传媒MV在线播放高清MBA| 毛耸耸性XXXX毛耸耸| 免费一对一真人视频| 男女啪啪摸下面喷水网站| 年轻漂亮的人妻被公侵犯BD免费版 | 精品久久久久久久无码| 精品少妇人妻AV免费久久久| 久久国产高潮流白浆免费观看| 久久精品国产亚洲AV蜜桃| 久久久久人妻精品一区三寸蜜桃| 久久久久人妻一区精品色| 浪潮AV激情高潮国产精品| 免费观看黄A级毛片| 欧美丰满美乳XXⅩ高潮WWW| 欧美性白人极品1819HD| 欧美做受三级级视频播放| 人妻激情另类乱人伦人妻| 日韩精品视频三区| 视频一区二区三区在线观看| 我的好妈妈中文字幕HD| 小雪被老汉各种姿势玩弄| 亚洲V欧美V日韩V国产V| 亚洲午夜无码极品久久| 在教室伦流澡到高潮H强圩电影| 14表妺好紧没带套18分钟| CEK俄罗斯BNAE0| 草莓视频免费观看| 国产成人精品久久一区二区 | 柚子猫原神甘雨视内射频| 10岁幼儿TREE小学生| WWWらだ天堂中文在线| 厨房人妻HD中文字幕69XX| 国产成人精品视频网站| 国产午夜鲁丝片AV无码| 精品国偷自产在线视频| 久久亚洲精品无码AV| 欧美超大胆裸体XX视频| 日本水蜜桃身体乳的美白效果| 双腿白浆白丝护士高潮视频| 西方37大但人文艺术A管77| 亚洲国产精品久久一线APP| 一区二区三区午夜无码视频| 99久E在线精品视频在线| 成 人 黄 色 网站 S色| 国产成人免费A在线视频| 国内揄拍国内精品少妇| 久久发布国产伦子伦精品| 男女爽到高潮的免费网站| 人人妻人人爽日日人人| 双飞两个丰满少妇11P| 亚洲AV午夜成人片精品网站 | 一本一本久久A久久精品综合| 40岁成熟女人牲交片20分钟| 成人国产精品秘片多多| 国产精品无码无片在线观看| 精品国产污污免费网站| 蜜臀av蜜臀一区二区三区| 人妻中文字幕AV无码专区| 无码精品人妻一区二区三区人妻斩 | 把腿张开老子cao烂你在线视频| 国产VIVODESHD精品| 孩教小UXXXⅩ精品| 两个男人吮她的花蒂和奶水视频| 欧美色成人综合天天影院| 四虎成人WWW成人影院| 亚洲成人av在线| 专干老肥女人88AV| 厨房征服丰满熟妇在线观看| 国产日产欧美一区二区蜜桃| 久久久亚洲欧洲日产国码是AV | 99久久人妻精品免费一区| 丰满人妻熟妇乱又伦精品视| 好紧我太爽了视频免费| 美女脱个精光露出奶头和尿口| 日韩成视频在线精品| 亚洲AV日韩综合一区尤物|