一,Netty簡介
1,什麼是Netty?爲什麼要使用Netty?
netty是jboss提供的一個java開源框架,netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可用性的網絡服務器和客戶端程序。也就是說netty是一個基於nio的編程框架,使用netty可以快速的開發出一個網絡應用。由於java 自帶的nio api使用起來非常複雜,並且還可能出現 Epoll Bug,這使得我們使用原生的nio來進行網絡編程存在很大的難度且非常耗時。但是netty良好的設計可以使開發人員快速高效的進行網絡應用開發。
2,Netty的特點
2.1 設計優雅。適用於各種傳輸類型的統一API,阻塞和非阻塞Socket基於靈活且可擴展的事件模型,可以清晰地分離關注點。2.2 使用方便 詳細記錄的Javadoc,用戶指南和示例 沒有其他依賴項,只需要提供JDK即可。2.3 高性能。延遲更低,減少資源消耗,最小化不必要的內存複製。2.4 安全完整的SSL / TLS和StartTLS支持。2.5 社區活躍,不斷更新 社區活躍,版本迭代週期短,發現的BUG可以被及時修復,同時,更多的新功能會被加入。
3,常用的使用場景
分佈式開源框架中dubbo,Zookeeper,RocketMQ底層rpc通訊使用就是netty.
3.1 互聯網行業
-
互聯網行業:在分佈式系統中,各個節點之間需要遠程服務調用,高性能的 RPC 框架必不可少,Netty 作爲異步高性能的通信框架,往往作爲基礎通信組件被這些 RPC 框架使用. -
典型的應用有:阿里分佈式服務框架 Dubbo 的 RPC 框架使用 Dubbo 協議進行節點間通信,Dubbo 協議默認使用 Netty 作爲基礎通信組件,用於實現各進程節點之間的內部通信.
3.2 遊戲行業
-
無論是手遊服務端還是大型的網絡遊戲,Java 語言得到了越來越廣泛的應用 -
Netty 作爲高性能的基礎通信組件, 提供了 TCP/UDP 和 HTTP 協議棧,方便定製和開發私有協議棧, 賬號登錄服務器 -
地圖服務器之間可以方便的通過 Netty 進行高性能的通信
二,Netty的功能特性和架構思想
1. Netty的整體架構
下面我們通過一張圖片大致瞭解一下netty框架前面有說,netty是基於NIO的一個網絡編程框架,故而上圖NIO的模型圖可以最爲間接的說明netty的一個基本流程--當一個Socket建立好之後,Thread並不會阻塞去接受這個Socket,而是將這個請求交給Selector,Selector會不斷的去遍歷所有的Socket,一旦有一個Socket建立完成,他會通知Thread,然後Thread處理完數據再返回給客戶端——這個過程是不阻塞的,這樣就能讓一個Thread處理更多的請求了.
2.Netty線程模型
netty的線程模型在主從Reactor多線程模型基礎上做了一定的改進,這個會在以後的文章中單獨敘述,這裏爲了文章的完整性所以簡述一下.
三,Netty核心API簡介
1.Bootstrap、ServerBootstrap
-
Bootstrap 意思是引導,一個 Netty 應用通常由一個 Bootstrap 開始,主要作用是配置整個 Netty 程序,串聯各個組件,Netty 中 Bootstrap 類是客戶端程序的啓動引導類,ServerBootstrap 是服務端啓動引導類 -
常見的方法有
-
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup),該方法用於服務器端,用來設置兩個 EventLoop; -
public B group(EventLoopGroup group) ,該方法用於客戶端,用來設置一個 EventLoop public B channel(Class<? extends C> channelClass),該方法用來設置一個服務器端的通道實現; -
public B option(ChannelOption option, T value),用來給 ServerChannel 添加配置; -
public ServerBootstrap childOption(ChannelOption childOption, T value),用來給接收到的通道添加配置; -
public ServerBootstrap childHandler(ChannelHandler childHandler),該方法用來設置業務處理類(自定義的 handler); -
public ChannelFuture bind(int inetPort) ,該方法用於服務器端,用來設置佔用的端口號; -
public ChannelFuture connect(String inetHost, int inetPort) ,該方法用於客戶端,用來連接服務器。
2.Future、ChannelFuture
-
Netty 中所有的 IO 操作都是異步的,不能立刻得知消息是否被正確處理。但是可以過一會等它執行完成或者直接註冊一個監聽,具體的實現就是通過 Future 和 ChannelFutures,他們可以註冊一個監聽,當操作執行成功或失敗時監聽會自動觸發註冊的監聽事件. -
常見的方法有:
-
Channel channel(),返回當前正在進行 IO 操作的通道 -
ChannelFuture sync(),等待異步操作執行完畢
3.Channel
-
Netty 網絡通信的組件,能夠用於執行網絡 I/O 操作; -
通過Channel 可獲得當前網絡連接的通道的狀態; -
通過Channel 可獲得 網絡連接的配置參數 (例如接收緩衝區大小); -
Channel 提供異步的網絡 I/O 操作(如建立連接,讀寫,綁定端口),異步調用意味着任何 I/O 調用都將立即返回,並且不保證在調 用結束時所請求的 I/O 操作已完成; -
調用立即返回一個 ChannelFuture 實例,通過註冊監聽器到 ChannelFuture 上,可以 I/O 操作成功、失敗或取消時回調通知調用方; -
支持關聯 I/O 操作與對應的處理程序 不同協議、不同的阻塞類型的連接都有不同的 Channel 類型與之對應; -
常用的 Channel 類型:
-
NioSocketChannel,異步的客戶端 TCP Socket 連接; -
NioServerSocketChannel,異步的服務器端 TCP Socket 連接; -
NioDatagramChannel,異步的 UDP 連接; -
NioSctpChannel,異步的客戶端 Sctp 連接; -
NioSctpServerChannel,異步的 Sctp 服務器端連接,這些通道涵蓋了 UDP 和 TCP 網絡 IO 以及文件 IO。
4.Selector
-
Netty 基於 Selector 對象實現 I/O 多路複用,通過 Selector 一個線程可以監聽多個連接的 Channel 事件; -
當向一個 Selector 中註冊 Channel 後,Selector 內部的機制就可以自動不斷地查詢(Select) 這些註冊的 Channel 是否有已就緒的 I/O 事件(例如可讀,可寫,網絡連接完成等),這樣程序就可以很簡單地使用一個線程高效地管理多個 Channel。
5.ChannelHandler 及其實現類
-
ChannelHandler 是一個接口,處理 I/O 事件或攔截 I/O 操作,並將其轉發到其 ChannelPipeline(業務處理鏈)中的下一個處理程序。 -
ChannelHandler 本身並沒有提供很多方法,因爲這個接口有許多的方法需要實現,方便使用期間,可以繼承它的子類. -
ChannelHandler 及其實現結構圖如下 1)ChannelInboundHandler 用於處理入站 I/O 事件。2)ChannelOutboundHandler 用於處理出站 I/O 操作。3)ChannelInboundHandlerAdapter 適配器用於處理入站 I/O 事件。4)ChannelOutboundHandlerAdapter 適配器用於處理出站 I/O 操作。5)ChannelDuplexHandler 適配器處理入站和出站事件。 -
Handler使用,我們經常需要自定義一個 Handler 類去繼承 ChannelInboundHandlerAdapter,然後通過重寫相應方法實現業務邏輯,下面列出一些常用的需要重寫的方法.
public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
public ChannelInboundHandlerAdapter() {
}
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelRegistered();
}
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelUnregistered();
}
//通道就緒事件
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
}
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
}
//通道讀取數據事件
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ctx.fireChannelRead(msg);
}
//數據讀取完畢事件
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelReadComplete();
}
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
ctx.fireUserEventTriggered(evt);
}
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelWritabilityChanged();
}
//通道發生異常事件
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.fireExceptionCaught(cause);
}
}
6.Pipeline 和 ChannelPipeline
-
ChannelPipeline 是一個 Handler 的集合,它負責處理和攔截 inbound 或者 outbound 的事件和操作,相當於一個貫穿 Netty 的鏈。(也可以這樣理解:ChannelPipeline 是 保存 ChannelHandler 的 List,用於處理或攔截 Channel 的入站事件和出站操作) -
ChannelPipeline 實現了一種高級形式的攔截過濾器模式,使用戶可以完全控制事件的處理方式,以及 Channel 中各個的 ChannelHandler 如何相互交互.
7.ChannelHandlerContex
-
保存 Channel 相關的所有上下文信息,同時關聯一個 ChannelHandler 對象; -
ChannelHandlerContext 中 包 含 一 個 具 體 的 事 件 處 理 器 ChannelHandler , 同 時ChannelHandlerContext 中也綁定了對應的 pipeline 和 Channel 的信息,方便對 ChannelHandler進行調用. -
常用方法 : 1)ChannelFuture close(),關閉通道 2)ChannelOutboundInvoker flush(),刷新 3)ChannelFuture writeAndFlush(Object msg) , 將 數 據 寫 到 ChannelPipeline 中 當 前 4)ChannelHandler 的下一個 ChannelHandler 開始處理(出棧).
8.ChannelOption
-
Netty 在創建 Channel 實例後,一般都需要設置 ChannelOption 參數。 -
ChannelOption 參數如下:
-
「ChannelOption.SO_BACKLOG」--對應 TCP/IP 協議 listen 函數中的 backlog 參數,用來初始化服務器可連接隊列大小。服 務端處理客戶端連接請求是順序處理的,所以同一時間只能處理一個客戶端連接。多個客戶端來的時候,服務端將不能處理的客戶端連接請求放在隊列中等待處理,backlog 參數指定了隊列的大小; -
「ChannelOption.SO_KEEPALIVE」--一直保持連接活動狀態.
9.EventLoopGroup 和其實現類 NioEventLoopGroup
-
EventLoopGroup 是一組 EventLoop 的抽象,Netty 爲了更好的利用多核 CPU 資源,一般會有多個 EventLoop 同時工作,每個 EventLoop 維護着一個 Selector 實例; -
EventLoopGroup 提供 next 接口,可以從組裏面按照一定規則獲取其中一個 EventLoop來處理任務。在 Netty 服務器端編程中,我們一般都需要提供兩個 EventLoopGroup,例如:BossEventLoopGroup 和 WorkerEventLoopGroup; -
通常一個服務端口即一個 ServerSocketChannel對應一個Selector 和一個EventLoop線程。BossEventLoop 負責接收客戶端的連接並將 SocketChannel 交給 WorkerEventLoopGroup 來進行 IO 處理.
10.Unpooled 類
-
Netty 提供一個專門用來操作緩衝區(即Netty的數據容器)的工具類 -
常用方法:
//通過給定的數據和字符編碼返回一個 ByteBuf 對象(類似於 NIO 中的 ByteBuffer 但有區別)
public static CompositeByteBuf compositeBuffer(int maxNumComponents) {
return new CompositeByteBuf(ALLOC, false, maxNumComponents);
}
好啦,以上內容就是Netty的一個基本介紹了,希望大家互相學習共同進步.
本文分享自微信公衆號 - 程序員小躍(runningdimple)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。