精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

徹底搞懂 Netty 線程模型

開發(fā) 前端
在學(xué)習(xí)Netty 之前我們最好先掌握 BIO、NIO、AIO 基礎(chǔ)知識,前面我們已經(jīng)花了三篇文章去講這些知識。我們開始來學(xué)習(xí) Netty 的具體知識了,本文就Netty線程模型展開分析。

 前言

  • BIO 、NIO 、AIO 總結(jié)
  • Unix網(wǎng)絡(luò)編程中的五種IO模型
  • 深入理解IO多路復(fù)用實現(xiàn)機制

在學(xué)習(xí)Netty 之前我們最好先掌握 BIO、NIO、AIO 基礎(chǔ)知識,前面我們已經(jīng)花了三篇文章去講這些知識。我們開始來學(xué)習(xí) Netty 的具體知識了,本文就Netty線程模型展開分析。

基本概念
IO 模型

  • BIO:同步阻塞模型;
  • NIO:基于IO多路復(fù)用技術(shù)的“非阻塞同步”IO模型。簡單來說,內(nèi)核將可讀可寫事件通知應(yīng)用,由應(yīng)用主動發(fā)起讀寫事件;
  • AIO:非阻塞異步IO模型。簡單來說,內(nèi)核將讀完成事件通知應(yīng)用,讀操作由內(nèi)核完成,應(yīng)用只需要操作數(shù)據(jù)即可;應(yīng)用做異步寫操作時立即返回,內(nèi)核會進行寫操作排隊并執(zhí)行寫操作。

NIO 和 AIO 不同之處在于應(yīng)用是否進行真正的讀寫操作。

reactor 和 proactor 模型

  • reactor:基于NIO技術(shù),可讀可寫時通知應(yīng)用;
  • proactor:基于AIO技術(shù),讀完成時通知應(yīng)用,寫操作應(yīng)用通知內(nèi)核。

Netty認(rèn)識
Netty是Java領(lǐng)域有名的開源網(wǎng)絡(luò)庫,特點是高性能和高擴展性,因此很多流行的框架都是基于它來構(gòu)建的,比如我們熟知的Dubbo、Rocketmq、Hadoop等。

通過前面 NIO 的學(xué)習(xí)可以看到,NIO 的類庫和API 繁雜,例如 Selector、 ServerSocketChannel、 SocketChannel、 ByteBuffer等這些對于從事應(yīng)用層的程序員來說,使用起來開發(fā)工作量和難度都非常大。另外客戶端面臨斷連重連、 網(wǎng)絡(luò)閃斷、心跳處理、半包讀寫、 網(wǎng)絡(luò)擁塞 和異常流的處理等等。

Netty 對 JDK 自帶的 NIO 的 API 進行了良好的封裝,解決了上述問題。且Netty擁有高性能、 吞吐量更高,延遲更低,減少資源消耗,最小化不必要的內(nèi)存復(fù)制等優(yōu)點。

Netty 現(xiàn)在都在用的是4.x,5.x版本已經(jīng)廢棄,Netty 4.x 需要JDK 6以上版本支持。

在了解Netty使用場景后,本節(jié)將從IO模型的演進角度來分析Netty線程模型,通過并發(fā)編程之父Doug Lea所寫《Scalable IO in Java》中涉及的一些IO處理模式,一步一步深入理解Netty線程模型的“進化歷史”。

《Scalable IO in Java》:

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

Netty使用場景

  1. 互聯(lián)網(wǎng)行業(yè):在分布式系統(tǒng)中,各個節(jié)點之間需要遠(yuǎn)程服務(wù)調(diào)用,高性能的 RPC 框架必不可少,Netty 作為異步高性能的通信框架,往往作為基礎(chǔ)通信組件被這些 RPC 框架使用。典型的應(yīng)用有:阿里分布式服務(wù)框架 Dubbo 的 RPC 使用 Dubbo 協(xié)議進行通信,Dubbo 協(xié)議默認(rèn)使用 Netty 作為基礎(chǔ)通信組件,用于實現(xiàn)各進程節(jié)點之間的內(nèi)部通信;消息中間件Rocketmq底層也是用的Netty作為基礎(chǔ)通信組件。
  2. 游戲行業(yè):無論是手游服務(wù)端還是大型的網(wǎng)絡(luò)游戲,Java 語言都得到了越來越廣泛的應(yīng)用。Netty 作為高性能的基礎(chǔ)通信組件,它本身提供了 TCP/UDP 和 HTTP 協(xié)議棧。
  3. 大數(shù)據(jù)領(lǐng)域:經(jīng)典的 Hadoop 的高性能通信和序列化組件 Avro 的 RPC 框架,默認(rèn)采用 Netty 進行跨節(jié)點通信,它的 Netty Service 是基于 Netty 框架二次封裝實現(xiàn)。

Netty相關(guān)開源項目:

https://netty.io/wiki/related-projects.html

IO處理模式演進
基本上所有的網(wǎng)絡(luò)處理程序都遵循以下基本的處理(handler)流程:

  1. Read request (接收二進制數(shù)據(jù))
  2. Decode request (解碼為可讀數(shù)據(jù))
  3. Process service (對數(shù)據(jù)進行處理產(chǎn)生結(jié)果)
  4. Encode reply (將結(jié)果編碼為二進制數(shù)據(jù))
  5. Send reply (返回結(jié)果)

傳統(tǒng)網(wǎng)絡(luò)服務(wù)器會為每一個連接的處理開啟一個新的線程,即我們前面所說的BIO模型(多線程模式),我們可以看下大致的示意圖:

上圖為 BIO版本

BIO模型對于每一個請求都分發(fā)給一個線程(可以理解為一個handler),每個handler中都獨自處理上面1-5流程。這種模型的適用場景和瓶頸可以查看《BIO 、NIO 、AIO 總結(jié)》。

改進:采用基于事件驅(qū)動的設(shè)計,當(dāng)有事件觸發(fā)時,才會調(diào)用處理器進行數(shù)據(jù)處理(非阻塞)。這就是對應(yīng)的NIO線程模型。

上圖為單線程版事件驅(qū)動模型,可以理解為NIO單線程版本

上面用到了 Reactor 模式。關(guān)于 Reactor 模式的兩個概念:

  • Reactor:負(fù)責(zé)響應(yīng) IO 事件,當(dāng)檢測到一個新的事件,將其發(fā)送給相應(yīng)的 Handler 去處理。
  • Handler:負(fù)責(zé)處理非阻塞的行為,標(biāo)識系統(tǒng)管理的資源,同時將 Handler 與事件綁定。

注意:Reactor 為單個線程,如上圖所示:不僅需要處理客戶端的 accept 連接請求,同時也要負(fù)責(zé)分發(fā)(dispatch)讀寫請求到處理器中。由于只有單個線程處理各種請求,所以要求處理器中的業(yè)務(wù)需要能夠快速處理完。

改進:現(xiàn)在的服務(wù)器基本上是多核 CPU,那么在多處理器場景下,為實現(xiàn)服務(wù)的高性能我們可以有目的的采用多線程模式處理業(yè)務(wù)。

上圖為多線程版本事件驅(qū)動模型,可以理解為NIO多線程版本

通過與NIO單線程模型相比,增加了worker線程池,專門用于處理非IO操作(decode、compute、encode),大大提高了工作效率。

這種模型下,客戶端發(fā)送過來的連接和注冊還是由主線程 Reactor 統(tǒng)一去處理,只不過客戶端連接成功后的后續(xù)事件分發(fā)給 worker 線程池去處理。

但是,當(dāng)客戶端短時間內(nèi)幾十萬或者上百萬條連接請求的時候(雙十一、春運搶票),單個 Rector 不僅要處理注冊事件,也要同時分發(fā)任務(wù)到 worker 線程池,由于分發(fā)也是比較耗時的操作,有可能會導(dǎo)致阻塞。

繼續(xù)改進:將Reactor 拆分為兩部分

上圖為主從NIO模型

如上圖所示,在這種模型下,mainReactor 專門負(fù)責(zé)新客戶端的連接操作,建立通道(channel),然后將一定事件內(nèi)的 channel 注冊到另外一個 subReactor,subReactor 負(fù)責(zé)將客戶端的讀寫請求交給線程池處理。這樣即使幾十萬個請求同時到來也無所謂了。

通俗理解,mainReactor就是大總管,只負(fù)責(zé)接口,subReactor就是一個員工,負(fù)責(zé)給總管接待客戶提供服務(wù)。

Netty線程模型
通過對 《 Scalable IO in Java 》里的一些 IO 處理模式理解, Netty的線程模型就是由上面主從NIO模型演變來的,是基于Reactor模型的。

如下圖所示,Boos Group 就是上面提到的 mainReactor,與上面不同在于 Worker Group,它可以理解為一組 subReactor,即在大總管下面有多個員工來干活,每次接收的客戶都均勻分配給不同員工。Netty 之所以單機支持百萬級別并發(fā)量,就是因為一主多從的線程模型。

需要說明的是,Netty 的線程模型并不是一成不變的。它通常采用一主多從,但是也可以根據(jù)實際需要配置啟動參數(shù),通過設(shè)置不同的啟動參數(shù),Netty 可以同時支持 “多主多從”。

下面是對上圖“一主多從” Netty 模型的詳細(xì)解釋:

  1. Netty 抽象除兩組線程池 BossGroup 和 WorkerGroup,BossGroup 專門負(fù)責(zé)接收客戶端的連接,WorkerGroup 專門負(fù)責(zé)網(wǎng)絡(luò)的讀寫。
  2. BossGroup 和 WorkerGroup 類型都是 NioEventLoopGroup。
  3. NioEventLoopGroup 相當(dāng)于一個事件循環(huán)線程組,這個組中含有多個事件循環(huán)線程,每一個事件循環(huán)線程是 NioEventLoop。
  4. 每個 NioEventLoop 都有一個 selector,用于監(jiān)聽注冊在其上的 socketChannel 的網(wǎng)絡(luò)通訊。
  5. 每個 Boss NioEventLoop 線程內(nèi)部循環(huán)執(zhí)行的步驟有 3 步:處理accept事件,與 client 建立連接,生成 NioSocketChannel;將NioSocketChannel 注冊到某個 worker NioEventLoop 上的 selector;處理任務(wù)隊列的任務(wù),即runAllTasks。
  6. 每個 worker NIOEvent'Loop線程循環(huán)執(zhí)行的步驟:輪詢注冊到最近的 selector 上所有的 NioSocketChannel 的 read、write 事件;處理 I/O 事件,即 read、write事件,在對應(yīng)的NioScoketChannel 處理業(yè)務(wù);runAllTask 處理任務(wù)隊列 TaskQueue 的任務(wù),一些耗時的業(yè)務(wù)處理一般可以放入 TaskQueue 中,這樣不影響數(shù)據(jù)在 pipeline 中的流動處理。
  7. 每個 worker NIOEventLoop 處理 NioSocketChannel 業(yè)務(wù)時,會使用 pipeline (管道),管道中維護來很多 handler 處理器用來處理 channel 中的數(shù)據(jù)。

Netty 模塊組件
Bootstrap、ServerBootstrap
Bootstrap 意思是引導(dǎo),一個 Netty 應(yīng)用通常由一個 Bootstrap 開始,主要作用是配置整個 Netty程序,通過鏈?zhǔn)秸{(diào)用串聯(lián)各個組件。Netty 中 Bootstrap 類是客戶端程序的啟動引導(dǎo)類,ServerBootstrap 是服務(wù)端 啟動引導(dǎo)類。

Future、ChannelFuture
正如前面介紹,在 Netty 中所有的 IO 操作都是異步的,不能立刻得知消息是否被正確處理。但是可以過一會等它執(zhí)行完成或者直接注冊一個監(jiān)聽,具體的實現(xiàn)就是通過 Future 和 ChannelFutures,他們可以注冊一個監(jiān)聽,當(dāng)操作執(zhí)行成功或失敗時監(jiān)聽會自動觸發(fā)注冊的監(jiān)聽事件。

Channel
Netty 網(wǎng)絡(luò)通信的組件,能夠用于執(zhí)行網(wǎng)絡(luò) I/O 操作。Channel 為用戶提供:

  1. 當(dāng)前網(wǎng)絡(luò)連接的通道的狀態(tài)(例如是否打開?是否已連接?)
  2. 網(wǎng)絡(luò)連接的配置參數(shù) (例如接收緩沖區(qū)大小)
  3. 提供異步的網(wǎng)絡(luò) I/O 操作(如建立連接,讀寫,綁定端口),異步調(diào)用意味著任何 I/O 調(diào)用都將立即返回,并且不保證在調(diào)用結(jié)束時所請求的 I/O 操作已完成。
  4. 調(diào)用立即返回一個 ChannelFuture 實例,通過注冊監(jiān)聽器到 ChannelFuture 上,可以 I/O 操作成功、失敗或取消時回調(diào)通知調(diào)用方。
  5. 支持關(guān)聯(lián) I/O 操作與對應(yīng)的處理程序。不同協(xié)議、不同的阻塞類型的連接都有不同的Channel 類型與之對應(yīng)。下面是一些常用的 Channel 類型:
  1. NioSocketChannel,異步的客戶端 TCP Socket 連接。(最常用) 
  2. NioServerSocketChannel,異步的服務(wù)器端 TCP Socket 連接 
  3. NioDatagramChannel,異步的 UDP 連接 
  4. NioSctpChannel,異步的客戶端 Sctp 連接 
  5. NioSctpServerChannel,異步的 Sctp 服務(wù)器端連接,這些通道涵蓋了 UDP 和 TCP 網(wǎng)絡(luò) IO 以及文件 IO。 

Selector
Netty 基于 Selector 對象實現(xiàn) I/O 多路復(fù)用,通過 Selector 一個線程可以監(jiān)聽多個連接的 Channel 事件。當(dāng)向一個 Selector 中注冊 Channel 后,Selector 內(nèi)部的機制就可以自動不斷地查詢(Select) 這些注冊的 Channel 是否有已就緒的 I/O 事件(例如可讀,可寫,網(wǎng)絡(luò)連接完成等),這樣程序就可以很簡單地使用一個線程高效地管理多個 Channel 。

NioEventLoop
NioEventLoop 中維護了一個線程和任務(wù)隊列,支持異步提交執(zhí)行任務(wù),線程啟動時會調(diào)用 NioEventLoop 的 run 方法,執(zhí)行 I/O 任務(wù)和非 I/O 任務(wù):

  1. I/O 任務(wù)即 selectionKey 中 ready 的事件,如 accept、connect、read、write 等,由 processSelectedKeys 方法觸發(fā)。
  2. 非 IO 任務(wù),添加到 taskQueue 中的任務(wù),如 register0、bind0 等任務(wù),由 runAllTasks 方法觸發(fā)。

NioEventLoopGroup
NioEventLoopGroup,主要管理 eventLoop 的生命周期,可以理解為一個線程池,內(nèi)部維護了一組線程,每個線程(NioEventLoop)負(fù)責(zé)處理多個 Channel 上的事件,而一個 Channel 只對應(yīng)于一個線程。

ChannelHandler
ChannelHandler 是一個接口,處理 I/O 事件或攔截 I/O 操作,并將其轉(zhuǎn)發(fā)到其 ChannelPipeline(業(yè)務(wù)處理鏈)中的下一個處理程序。ChannelHandler 本身并沒有提供很多方法,因為這個接口有許多的方法需要實現(xiàn),方便使用期間,可以繼承它的子類:

  1. ChannelInboundHandler 用于處理入站 I/O 事件 
  2. ChannelOutboundHandler 用于處理出站 I/O 操作 

或者使用以下適配器類:

  1. ChannelInboundHandlerAdapter 用于處理入站 I/O 事件。 
  2. ChannelOutboundHandlerAdapter 用于處理出站 I/O 操作。 

ChannelHandlerContext
保存 Channel 相關(guān)的所有上下文信息,同時關(guān)聯(lián)一個 ChannelHandler 對象。

ChannelPipline
保存 ChannelHandler 的 List,用于處理或攔截 Channel 的入站事件和出站操作。ChannelPipeline 實現(xiàn)了一種高級形式的攔截過濾器模式,使用戶可以完全控制事件的處理方式,以及 Channel 中各個的 ChannelHandler 如何相互交互。在 Netty 中每個 Channel 都有且僅有一個 ChannelPipeline 與之對應(yīng),它們的組成關(guān)系如下:

一個 Channel 包含了一個 ChannelPipeline,而 ChannelPipeline 中又維護了一個由 ChannelHandlerContext 組成的雙向鏈表,并且每個 ChannelHandlerContext 中又關(guān)聯(lián)著一個 ChannelHandler。read事件(入站事件)和write事件(出站事件)在一個雙向鏈表中,入站事件會從鏈表 head 往后傳遞到最后一個入站的 handler,出站事件會從鏈表 tail 往前傳遞到最前一個出站的 handler,兩種類型的 handler 互不干擾。

Netty通訊示例
Netty的maven依賴

  1. <dependencies> 
  2.  <dependency> 
  3.   <groupId>io.netty</groupId> 
  4.         <artifactId>netty-all</artifactId> 
  5.         <version>4.1.52.Final</version> 
  6.     </dependency> 
  7. </dependencies> 

服務(wù)端代碼

  1. package com.niuh.netty.base; 
  2.  
  3. import io.netty.bootstrap.ServerBootstrap; 
  4. import io.netty.channel.ChannelFuture; 
  5. import io.netty.channel.ChannelInitializer; 
  6. import io.netty.channel.ChannelOption; 
  7. import io.netty.channel.EventLoopGroup; 
  8. import io.netty.channel.nio.NioEventLoopGroup; 
  9. import io.netty.channel.socket.SocketChannel; 
  10. import io.netty.channel.socket.nio.NioServerSocketChannel; 
  11.  
  12. public class NettyServer { 
  13.  
  14.     public static void main(String[] args) throws Exception { 
  15.         //創(chuàng)建兩個線程組bossGroup和workerGroup, 含有的子線程NioEventLoop的個數(shù)默認(rèn)為cpu核數(shù)的兩倍 
  16.         // bossGroup只是處理連接請求 ,真正的和客戶端業(yè)務(wù)處理,會交給workerGroup完成 
  17.         EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
  18.         EventLoopGroup workerGroup = new NioEventLoopGroup(); 
  19.         try { 
  20.             //創(chuàng)建服務(wù)器端的啟動對象 
  21.             ServerBootstrap bootstrap = new ServerBootstrap(); 
  22.             //使用鏈?zhǔn)骄幊虂砼渲脜?shù) 
  23.             bootstrap.group(bossGroup, workerGroup) //設(shè)置兩個線程組 
  24.                     .channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作為服務(wù)器的通道實現(xiàn) 
  25.                     // 初始化服務(wù)器連接隊列大小,服務(wù)端處理客戶端連接請求是順序處理的,所以同一時間只能處理一個客戶端連接。 
  26.                     // 多個客戶端同時來的時候,服務(wù)端將不能處理的客戶端連接請求放在隊列中等待處理 
  27.                     .option(ChannelOption.SO_BACKLOG, 1024) 
  28.                     .childHandler(new ChannelInitializer<SocketChannel>() {//創(chuàng)建通道初始化對象,設(shè)置初始化參數(shù) 
  29.  
  30.                         @Override 
  31.                         protected void initChannel(SocketChannel ch) throws Exception { 
  32.                             //對workerGroup的SocketChannel設(shè)置處理器 
  33.                             ch.pipeline().addLast(new NettyServerHandler()); 
  34.                         } 
  35.                     }); 
  36.             System.out.println("netty server start。。"); 
  37.             //綁定一個端口并且同步, 生成了一個ChannelFuture異步對象,通過isDone()等方法可以判斷異步事件的執(zhí)行情況 
  38.             //啟動服務(wù)器(并綁定端口),bind是異步操作,sync方法是等待異步操作執(zhí)行完畢 
  39.             ChannelFuture cf = bootstrap.bind(9000).sync(); 
  40.             //給cf注冊監(jiān)聽器,監(jiān)聽我們關(guān)心的事件 
  41.             /*cf.addListener(new ChannelFutureListener() { 
  42.                 @Override 
  43.                 public void operationComplete(ChannelFuture future) throws Exception { 
  44.                     if (cf.isSuccess()) { 
  45.                         System.out.println("監(jiān)聽端口9000成功"); 
  46.                     } else { 
  47.                         System.out.println("監(jiān)聽端口9000失敗"); 
  48.                     } 
  49.                 } 
  50.             });*/ 
  51.             //對通道關(guān)閉進行監(jiān)聽,closeFuture是異步操作,監(jiān)聽通道關(guān)閉 
  52.             // 通過sync方法同步等待通道關(guān)閉處理完畢,這里會阻塞等待通道關(guān)閉完成 
  53.             cf.channel().closeFuture().sync(); 
  54.         } finally { 
  55.             bossGroup.shutdownGracefully(); 
  56.             workerGroup.shutdownGracefully(); 
  57.         } 
  58.     } 

服務(wù)端所注冊的自定義回調(diào)函數(shù) NettyServerHandler:

  1. package com.niuh.netty.base; 
  2.  
  3. import io.netty.buffer.ByteBuf; 
  4. import io.netty.buffer.Unpooled; 
  5. import io.netty.channel.ChannelHandlerContext; 
  6. import io.netty.channel.ChannelInboundHandlerAdapter; 
  7. import io.netty.util.CharsetUtil; 
  8.  
  9. /** 
  10.  * 自定義Handler需要繼承netty規(guī)定好的某個HandlerAdapter(規(guī)范) 
  11.  */ 
  12. public class NettyServerHandler extends ChannelInboundHandlerAdapter { 
  13.  
  14.     /** 
  15.      * 讀取客戶端發(fā)送的數(shù)據(jù) 
  16.      * 
  17.      * @param ctx 上下文對象, 含有通道channel,管道pipeline 
  18.      * @param msg 就是客戶端發(fā)送的數(shù)據(jù) 
  19.      * @throws Exception 
  20.      */ 
  21.     @Override 
  22.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
  23.         System.out.println("服務(wù)器讀取線程 " + Thread.currentThread().getName()); 
  24.         //Channel channel = ctx.channel(); 
  25.         //ChannelPipeline pipeline = ctx.pipeline(); //本質(zhì)是一個雙向鏈接, 出站入站 
  26.         //將 msg 轉(zhuǎn)成一個 ByteBuf,類似NIO 的 ByteBuffer 
  27.         ByteBuf buf = (ByteBuf) msg; 
  28.         System.out.println("客戶端發(fā)送消息是:" + buf.toString(CharsetUtil.UTF_8)); 
  29.     } 
  30.  
  31.     /** 
  32.      * 數(shù)據(jù)讀取完畢處理方法 
  33.      * 
  34.      * @param ctx 
  35.      * @throws Exception 
  36.      */ 
  37.     @Override 
  38.     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 
  39.         ByteBuf buf = Unpooled.copiedBuffer("HelloClient".getBytes(CharsetUtil.UTF_8)); 
  40.         ctx.writeAndFlush(buf); 
  41.     } 
  42.  
  43.     /** 
  44.      * 處理異常, 一般是需要關(guān)閉通道 
  45.      * 
  46.      * @param ctx 
  47.      * @param cause 
  48.      * @throws Exception 
  49.      */ 
  50.     @Override 
  51.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
  52.         ctx.close(); 
  53.     } 

這個類繼承了ChannelInboundHandlerAdapter的幾個方法:

  • channelRead方法:當(dāng)客戶端與服務(wù)端連通好之后,客戶端發(fā)數(shù)據(jù)時,服務(wù)端會主動調(diào)用這個方法。
  • channelReadComplete方法:數(shù)據(jù)處理完畢的方法,ctx.writeAndFlush()就可以往客戶端寫回數(shù)據(jù)了。

客戶端代碼

  1. package com.niuh.netty.base; 
  2.  
  3. import io.netty.bootstrap.Bootstrap; 
  4. import io.netty.channel.ChannelFuture; 
  5. import io.netty.channel.ChannelInitializer; 
  6. import io.netty.channel.EventLoopGroup; 
  7. import io.netty.channel.nio.NioEventLoopGroup; 
  8. import io.netty.channel.socket.SocketChannel; 
  9. import io.netty.channel.socket.nio.NioSocketChannel; 
  10.  
  11. public class NettyClient { 
  12.     public static void main(String[] args) throws Exception { 
  13.         //客戶端需要一個事件循環(huán)組 
  14.         EventLoopGroup group = new NioEventLoopGroup(); 
  15.         try { 
  16.             //創(chuàng)建客戶端啟動對象 
  17.             //注意客戶端使用的不是ServerBootstrap而是Bootstrap 
  18.             Bootstrap bootstrap = new Bootstrap(); 
  19.             //設(shè)置相關(guān)參數(shù) 
  20.             bootstrap.group(group) //設(shè)置線程組 
  21.                     .channel(NioSocketChannel.class) // 使用NioSocketChannel作為客戶端的通道實現(xiàn) 
  22.                     .handler(new ChannelInitializer<SocketChannel>() { 
  23.                         @Override 
  24.                         protected void initChannel(SocketChannel ch) throws Exception { 
  25.                             //加入處理器 
  26.                             ch.pipeline().addLast(new NettyClientHandler()); 
  27.                         } 
  28.                     }); 
  29.  
  30.             System.out.println("netty client start。。"); 
  31.             //啟動客戶端去連接服務(wù)器端 
  32.             ChannelFuture cf = bootstrap.connect("127.0.0.1", 9000).sync(); 
  33.             //對通道關(guān)閉進行監(jiān)聽 
  34.             cf.channel().closeFuture().sync(); 
  35.         } finally { 
  36.             group.shutdownGracefully(); 
  37.         } 
  38.     } 

客戶端自定義回調(diào)函數(shù):

  1. package com.niuh.netty.base; 
  2.  
  3. import io.netty.buffer.ByteBuf; 
  4. import io.netty.buffer.Unpooled; 
  5. import io.netty.channel.ChannelHandlerContext; 
  6. import io.netty.channel.ChannelInboundHandlerAdapter; 
  7. import io.netty.util.CharsetUtil; 
  8.  
  9. public class NettyClientHandler extends ChannelInboundHandlerAdapter { 
  10.  
  11.     /** 
  12.      * 當(dāng)客戶端連接服務(wù)器完成就會觸發(fā)該方法 
  13.      * 
  14.      * @param ctx 
  15.      * @throws Exception 
  16.      */ 
  17.     @Override 
  18.     public void channelActive(ChannelHandlerContext ctx) throws Exception { 
  19.         ByteBuf buf = Unpooled.copiedBuffer("HelloServer".getBytes(CharsetUtil.UTF_8)); 
  20.         ctx.writeAndFlush(buf); 
  21.     } 
  22.  
  23.     //當(dāng)通道有讀取事件時會觸發(fā),即服務(wù)端發(fā)送數(shù)據(jù)給客戶端 
  24.     @Override 
  25.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
  26.         ByteBuf buf = (ByteBuf) msg; 
  27.         System.out.println("收到服務(wù)端的消息:" + buf.toString(CharsetUtil.UTF_8)); 
  28.         System.out.println("服務(wù)端的地址: " + ctx.channel().remoteAddress()); 
  29.     } 
  30.  
  31.     @Override 
  32.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
  33.         cause.printStackTrace(); 
  34.         ctx.close(); 
  35.     } 

與NettyServerHandler類似,其中的channelActive()方法是當(dāng)客戶端與服務(wù)器連接完成時候就會執(zhí)行的方法。

看完代碼,我們發(fā)現(xiàn)Netty架的目標(biāo)就是讓你的業(yè)務(wù)邏輯從網(wǎng)絡(luò)基礎(chǔ)應(yīng)用編碼中分離出來,讓你可以專 注業(yè)務(wù)的開發(fā),而不需寫一大堆類似NIO的網(wǎng)絡(luò)處理操作。

ByteBuf 理解
從結(jié)構(gòu)上來說,ByteBuf 由一串字節(jié)數(shù)組構(gòu)成。數(shù)組中每個字節(jié)用來存放信息。

ByteBuf 提供了兩個索引,一個用于讀取數(shù)據(jù),一個用于寫入數(shù)據(jù)。這兩個索引通過在字節(jié)數(shù)組中移動,來定位需要讀或者寫信息的位置。

  • 當(dāng)從 ByteBuf 讀取時,它的 readerIndex(讀索引)將會根據(jù)讀取的字節(jié)數(shù)遞增。
  • 同樣,當(dāng)寫 ByteBuf 時,它的 writerIndex 也會根據(jù)寫入的字節(jié)數(shù)進行遞增。

ByteBuf.png

需要注意的是極限的情況是 readerIndex 剛好讀到了 writerIndex 寫入的地方。如果 readerIndex 超過了 writerIndex 的時候,Netty 會拋出 IndexOutOf-BoundsException 異常。

示例代碼

  1. package com.niuh.netty.base; 
  2.  
  3. import io.netty.buffer.ByteBuf; 
  4. import io.netty.buffer.Unpooled; 
  5. import io.netty.util.CharsetUtil; 
  6.  
  7. public class NettyByteBuf { 
  8.     public static void main(String[] args) { 
  9.         // 創(chuàng)建byteBuf對象,該對象內(nèi)部包含一個字節(jié)數(shù)組byte[10] 
  10.         // 通過readerindex和writerIndex和capacity,將buffer分成三個區(qū)域 
  11.         // 已經(jīng)讀取的區(qū)域:[0,readerindex) 
  12.         // 可讀取的區(qū)域:[readerindex,writerIndex) 
  13.         // 可寫的區(qū)域: [writerIndex,capacity) 
  14.         ByteBuf byteBuf = Unpooled.buffer(10); 
  15.         System.out.println("byteBuf=" + byteBuf); 
  16.  
  17.         for (int i = 0; i < 8; i++) { 
  18.             byteBuf.writeByte(i); 
  19.         } 
  20.         System.out.println("byteBuf=" + byteBuf); 
  21.  
  22.         for (int i = 0; i < 5; i++) { 
  23.             System.out.println(byteBuf.getByte(i)); 
  24.         } 
  25.         System.out.println("byteBuf=" + byteBuf); 
  26.  
  27.         for (int i = 0; i < 5; i++) { 
  28.             System.out.println(byteBuf.readByte()); 
  29.         } 
  30.         System.out.println("byteBuf=" + byteBuf); 
  31.  
  32.  
  33.         //用Unpooled工具類創(chuàng)建ByteBuf 
  34.         ByteBuf byteBuf2 = Unpooled.copiedBuffer("hello,zhangsan!", CharsetUtil.UTF_8); 
  35.         //使用相關(guān)的方法 
  36.         if (byteBuf2.hasArray()) { 
  37.             byte[] content = byteBuf2.array(); 
  38.             //將 content 轉(zhuǎn)成字符串 
  39.             System.out.println(new String(content, CharsetUtil.UTF_8)); 
  40.             System.out.println("byteBuf=" + byteBuf2); 
  41.  
  42.             System.out.println(byteBuf2.readerIndex()); // 0 
  43.             System.out.println(byteBuf2.writerIndex()); // 12 
  44.             System.out.println(byteBuf2.capacity()); // 36 
  45.  
  46.             System.out.println(byteBuf2.getByte(0)); // 獲取數(shù)組0這個位置的字符h的ascii碼,h=104 
  47.  
  48.             int len = byteBuf2.readableBytes(); //可讀的字節(jié)數(shù)  12 
  49.             System.out.println("len=" + len); 
  50.  
  51.             //使用for取出各個字節(jié) 
  52.             for (int i = 0; i < len; i++) { 
  53.                 System.out.println((char) byteBuf2.getByte(i)); 
  54.             } 
  55.  
  56.             //范圍讀取 
  57.             System.out.println(byteBuf2.getCharSequence(0, 6, CharsetUtil.UTF_8)); 
  58.             System.out.println(byteBuf2.getCharSequence(6, 6, CharsetUtil.UTF_8)); 
  59.         } 
  60.     } 

PS:以上代碼提交在 Github :https://github.com/Niuh-Study/niuh-netty.git

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2025-07-01 06:05:34

2020-07-02 09:15:59

Netty內(nèi)存RPC

2022-04-12 08:00:17

socket 編程網(wǎng)絡(luò)編程網(wǎng)絡(luò) IO 模型

2021-07-16 11:35:20

Java線程池代碼

2022-04-11 10:56:43

線程安全

2025-04-21 04:00:00

2024-09-04 16:19:06

語言模型統(tǒng)計語言模型

2024-01-03 13:39:00

JS,Javascrip算法

2025-01-13 16:00:00

服務(wù)網(wǎng)關(guān)分布式系統(tǒng)架構(gòu)

2025-04-11 05:55:00

2023-10-18 10:55:55

HashMap

2025-06-30 00:32:43

策略模式算法MyBatis

2017-12-05 17:44:31

機器學(xué)習(xí)CNN卷積層

2025-05-06 01:14:00

系統(tǒng)編程響應(yīng)式

2022-09-29 15:39:10

服務(wù)器NettyReactor

2021-12-29 17:29:07

KubernetesEvents集群

2023-09-28 08:15:05

SpringBean加載

2021-10-11 11:58:41

Channel原理recvq

2023-05-29 08:12:38

2021-10-09 19:05:06

channelGo原理
點贊
收藏

51CTO技術(shù)棧公眾號

www.av成人| 91精品国产91久久综合| 午夜国产精品视频免费体验区| 一区二区三区欧美视频| 亚洲国产黄色片| 亚洲国产高清国产精品| 日韩欧美一级视频| 国产精品毛片无码| 久久综合九色综合欧美亚洲| 欧美精品在线免费观看| 高清一区在线观看| 四虎免费在线观看| 欧美精品网站| 欧美日韩国产精选| 欧美日韩一区二区三区在线观看免 | 中国极品少妇videossexhd| 麻豆视频在线观看免费网站| 欧美18免费视频| 亚洲激情在线播放| 欧美日韩亚洲在线| 成人午夜视频一区二区播放| 综合久久十次| 欧美一区二区三区四区视频| 亚洲在线观看一区| 国产真人无遮挡作爱免费视频| 久久97精品| 亚洲18女电影在线观看| 不卡视频一区二区| 欧美成欧美va| 91大神精品| 亚洲狠狠丁香婷婷综合久久久| 国内一区在线| 久久久久久久99| 91大神精品| 欧美精品tushy高清| 中日韩在线视频| 国产精品欧美综合亚洲| 97精品在线| 欧美一区二区三区四区视频| 国产精品久久久久9999小说| 大片免费播放在线视频| 日韩国产成人精品| 中文字幕欧美日韩| 国产高清999| 伊人在我在线看导航| 国产精品99久久久久| 欧美激情精品久久久久久黑人| 大尺度做爰床戏呻吟舒畅| 四虎视频在线精品免费网址| 尤物av一区二区| 一区二区在线观| 91精品大全| 国产电影一区在线| 91免费观看网站| 国产在线一二区| 一区二区三区日本久久久| 日本道在线观看一区二区| 亚洲五月六月| 香蕉视频在线看| 丁香激情综合五月| 国产99久久精品一区二区 夜夜躁日日躁 | 亚洲欧美网站| 色偷偷av一区二区三区| 天美一区二区三区| 国产精品亚洲综合在线观看| 4hu四虎永久在线影院成人| 人妻av无码专区| 青青草在线视频免费观看| 免费人成网站在线观看欧美高清| 久久99久久99精品免观看粉嫩| 9.1成人看片免费版| 亚洲国产天堂| 91精品一区二区三区久久久久久| 激情五月婷婷基地| 中文字幕在线免费观看视频| 亚洲女同一区二区| 日韩欧美视频一区二区三区四区| 精品人妻一区二区三区浪潮在线| 国产欧美二区| 日韩在线精品一区| 国产免费久久久久| 亚洲东热激情| 久热精品视频在线观看| 一级片视频免费看| 欧美激情网址| 亚洲无限av看| free性中国hd国语露脸| 亚洲天堂中文字幕在线观看| 亚洲国产福利在线| 欧美老熟妇乱大交xxxxx| 伊人久久亚洲| 日韩电影免费观看中文字幕| 国产男女无遮挡猛进猛出| 丝袜美腿一区| 亚瑟在线精品视频| 午夜精品久久久内射近拍高清| 色噜噜狠狠狠综合欧洲色8| 国产精品污www在线观看| 精品视频一区二区| 亚洲成熟女性毛茸茸| 国产一区二区三区观看| 国产精品免费在线免费| 欧美性猛交xxxx乱大交hd| 紧缚奴在线一区二区三区| 国产精品第三页| 区一区二在线观看| 在线亚洲一区| 1769国内精品视频在线播放| 国产一卡二卡在线| 久久亚洲一区| 国产精品久久久91| 国产成人无码www免费视频播放| xfplay精品久久| 久久人人九九| 四虎精品成人免费网站| 北条麻妃一区二区三区| 国产一区玩具在线观看| 九九热最新视频| 国产999精品久久久久久绿帽| 亚洲影院色无极综合| 国产男男gay体育生网站| 美腿丝袜亚洲综合| 精品久久久久久亚洲| 黄视频在线观看网站| 亚洲桃色在线一区| 黑人巨茎大战欧美白妇| 韩国日本一区| 婷婷一区二区三区| 无码aⅴ精品一区二区三区浪潮| а天堂中文最新一区二区三区| 91麻豆精品国产91久久久久久久久| 三级电影在线看| 欧美色综合网| 91亚洲精品久久久久久久久久久久| 你懂的视频在线| 中文字幕av不卡| 黄色免费观看视频网站| 日本精品另类| 欧美一区二区三区爱爱| 亚洲v国产v欧美v久久久久久| 在线亚洲伦理| 精品无码久久久久久久动漫| 黄页在线观看免费| 日韩一区二区中文字幕| 星空大象在线观看免费播放| 欧美成熟视频| 91传媒视频免费| 婷婷在线免费视频| 91香蕉视频污| 精品视频在线观看一区| 成人视屏在线观看| 欧美一级在线观看| 国产老头老太做爰视频| 精品中文字幕一区二区| 韩国一区二区三区美女美女秀 | 久久精品在线免费观看| 亚洲激情一区二区| 99久久er| 亚洲成人久久久久| 久久亚洲AV无码| 日韩综合在线视频| 日韩欧美亚洲在线| 日韩一区精品| 久久久999国产| 日本一级淫片色费放| 懂色av噜噜一区二区三区av| 男人添女荫道口女人有什么感觉| 成人爽a毛片免费啪啪红桃视频| 国产一区二区精品丝袜| 日韩xxx视频| av电影天堂一区二区在线| 香港三级韩国三级日本三级| 欧美亚洲二区| 欧美巨大黑人极品精男| 高h震动喷水双性1v1| 欧美色播在线播放| 在线观看中文av| 亚洲无线视频| 成人字幕网zmw| 91一区二区三区在线| 精品福利一区二区三区免费视频| 欧美色图17p| 先锋影音久久久| 婷婷久久青草热一区二区| a√中文在线观看| 日韩一区二区三区观看| 国产网址在线观看| 国产色爱av资源综合区| 青青草成人免费在线视频| 亚洲精品tv| 欧美激情2020午夜免费观看| 日韩毛片在线一区二区毛片| 欧美亚洲丝袜传媒另类| 国产艳俗歌舞表演hd| 日韩av中文在线观看| 天天在线免费视频| av一级久久| 韩国v欧美v日本v亚洲| 亚洲国产999| 日韩欧美一区视频| 疯狂试爱三2浴室激情视频| 成人激情小说乱人伦| 成人性生生活性生交12| 奇米亚洲欧美| 国产成人高清激情视频在线观看| 亚洲欧洲国产综合| 欧美色爱综合网| 国产性猛交xx乱| 奇米888四色在线精品| 欧美日韩喷水| 精品久久国产一区| 欧美精品中文字幕一区| 欧美一区二区少妇| 日韩欧美色综合| 久久久精品国产sm调教| 国产欧美一区二区精品忘忧草 | 日韩成人免费在线| 国产精品12345| 自产国语精品视频| 亚洲一区精品视频| 精品在线播放| 久久手机视频| av日韩精品| 亚洲一区二区少妇| 成人mm视频在线观看| 韩国日本不卡在线| 欧洲在线视频| 亚洲国产又黄又爽女人高潮的| 日韩毛片在线视频| 亚洲靠逼com| 日本黄色片免费观看| 国产精品免费av| 在线视频日韩欧美| 捆绑调教美女网站视频一区| 强开小嫩苞一区二区三区网站| 一区二区三区视频免费观看| 国产精品一区视频网站| 日韩在线伦理| 中文字幕亚洲综合久久| 色天堂在线视频| 亚洲精品日韩久久久| 中文字幕精品一区二| 亚洲人成亚洲人成在线观看图片| 久久久久久国产免费a片| 国产伦精品一区二区三区免费迷 | 国产传媒一区二区| 小早川怜子影音先锋在线观看| 欧美富婆性猛交| 天堂av资源在线观看| 欧美激情在线狂野欧美精品| 欧美午夜黄色| 精品亚洲国产成av人片传媒| 青青久草在线| 亚洲网站在线播放| 免费在线黄色影片| 一本久久综合亚洲鲁鲁| 超碰免费在线97| 欧美不卡在线视频| 免费黄色一级大片| 欧美日精品一区视频| 中文字幕一区二区三区四区视频| 欧美午夜一区二区| 国产有码在线观看| 黑人巨大精品欧美一区免费视频| 成人黄色短视频| av一区二区三区在线| 中文字幕在线播放视频| 国内国产精品久久| 国产精品久久久久久久99| 国产成人精品免费看| 一级黄色免费视频| 激情综合网最新| 91视频免费入口| 成人av网站在线| 日本少妇高潮喷水xxxxxxx| 国产精品欧美一区喷水| 欧美黑人猛猛猛| 欧美性猛交xxxx| 成人黄色免费网| 欧美一区二区三区视频在线 | 成人全视频在线观看在线播放高清| 91精品综合视频| 久久国产精品免费精品3p| 日本一区二区久久精品| 任你躁在线精品免费| 日本一区二区三区视频在线观看| 亚洲成av人片乱码色午夜| 国产午夜大地久久| 免费在线看成人av| 少妇熟女视频一区二区三区 | 一本久道久久综合中文字幕| 欧美黄色一级网站| 亚洲欧美在线观看| 亚洲欧美va天堂人熟伦| 亚洲伦在线观看| 免费av网站在线| 一本色道a无线码一区v| 国产精品毛片一区二区在线看舒淇| 亚洲激情小视频| 老司机在线永久免费观看| 国产综合在线看| 超碰在线视屏| 久久乐国产精品| 成人久久网站| 久久精品magnetxturnbtih| 99精品电影| 青青草影院在线观看| 一本一本久久| 无码人妻丰满熟妇啪啪网站| 国产精品丝袜一区| 800av免费在线观看| 欧美一区日本一区韩国一区| 日本一本草久在线中文| 欧美成人在线影院| 成人不卡视频| 欧美国产一区二区在线| 影音先锋日韩资源| 日韩成人精品视频在线观看| 国产丝袜美腿一区二区三区| 精品亚洲永久免费| 欧美精选在线播放| 国产免费av高清在线| 色偷偷av一区二区三区| 神马久久午夜| 高清不卡一区二区三区| 99久久99久久精品国产片桃花| 精品免费国产一区二区| 丝袜美腿亚洲一区| 男男做爰猛烈叫床爽爽小说| 亚洲精品国产精华液| 91国内精品视频| 中文字幕av一区中文字幕天堂| 日本不卡免费高清视频在线| 国产精品日韩一区二区免费视频| 亚洲国产一区二区三区在线播放| 一区二区在线播放视频| 26uuu亚洲综合色| 日韩手机在线观看| 欧美视频在线观看一区二区| 日韩一区二区三区中文字幕| 97精品国产97久久久久久免费| 草草视频在线一区二区| 999一区二区三区| 成人一区二区三区| 久久久久久久久97| 精品国产成人系列| 黄色影院在线看| 国产乱码精品一区二区三区不卡| 在线观看亚洲| 欧美在线一级片| 欧美午夜精品伦理| 黄色av网址在线免费观看| 久久99久国产精品黄毛片入口| 国产日本亚洲| 免费在线看黄色片| 成人av电影免费观看| 日本午夜视频在线观看| 日韩精品日韩在线观看| 美女日韩欧美| 国产超碰91| 亚洲国产婷婷| 超碰成人在线播放| 99久久久久免费精品国产| 欧美日韩综合在线观看| 亚洲欧美激情在线视频| 日韩三级电影视频| 国产女人水真多18毛片18精品| 99精品国产在热久久| 一本色道久久综合亚洲精品图片| 色婷婷综合在线| 日韩精品黄色| aa日韩免费精品视频一| 国产一区二区三区的电影| 国产亚洲精品熟女国产成人| 欧美日韩免费观看一区三区| 9191在线播放| 麻豆视频成人| 亚洲激情国产| 在线国产视频一区| 欧美狂野另类xxxxoooo| 欧美人与牲禽动交com| 玛丽玛丽电影原版免费观看1977 | 亚洲一二三专区| 国产又爽又黄免费软件| 欧美成人剧情片在线观看| 大伊香蕉精品在线品播放| 欧美日韩一级在线 | 免费成人黄色大片| 亚洲一区二区视频在线| 精品电影在线| 99三级在线| 日本aⅴ亚洲精品中文乱码| 久久久久久久极品内射| 亚洲天堂成人在线| 日本不卡1234视频| 伊人色综合影院| 91网站在线观看视频| 国产色片在线观看| 欧美一级片在线播放| 欧美一级三级|