1. 前言
本節主要講解服務端主啟動類 ServerBootstrap 的核心 API 的使用。
2. ServerBootstrap 流程
ServerBootstrap 的用法基本上都是固定的,一般對于新接觸 Netty 的同學來說,會覺得這些模板代碼比較多,難以理解。我們主要記住幾個核心配置即可。
- 指定線程模型: 通過.group(bossGroup, workerGroup) 給引導類配置兩大線程組,這個引導類的線程模型也就定型了。其中 bossGroup 表示監聽端口,accept 新連接的線程組;workerGroup 表示處理每一條連接的數據讀寫的線程組;
- 指定 IO 模型: 通過.channel(NioServerSocketChannel.class) 來指定 NIO 模型。如果指定 IO 模型為 BIO,那么這里配置上 OioServerSocketChannel.class 類型即可,通常都是使用 NIO,因為 Netty 的優勢就在于 NIO;
- 指定處理邏輯: 通過 childHandler () 方法,給這個引導類創建一個 ChannelInitializer,這里主要就是定義后續每條連接的數據讀寫,業務處理邏輯;
- 綁定端口號: 調用 bind (80),端口號自定義,不要和其他應用的端口號有沖突即可。
3. 核心方法
方法 | 說明 |
group() | 用來指定線程模型 |
channel() | 用來指定 IO 模型 |
handler() | 用來指定服務端通道需要處理的業務邏輯(了解) |
childHandler() | 用來指定客戶端通道需要處理的業務邏輯(掌握) |
attr() | 給服務端通道綁定自定義屬性(了解) |
childAttr() | 給客戶端通道綁定自定義屬性(掌握) |
option() | 給服務端通道設置配置(了解) |
childOption() | 給客戶端通道設置配置(了解) |
bind() | 用來綁定端口號 |
說明:客戶端和服務端連接之后,會維持一個 Channel 通道,可以給其指定邏輯處理器和屬性配置;當然,服務端啟動的時候它也是一個特殊的 Channel 通道。
在開發當中,需要我們去自定義的方法主要是 childHandler () 和 childAttr () 這兩個。childHandler () 用來綁定業務邏輯器,childAttr () 用來設置 Channel 屬性。比如:綁定用戶身份信息。其它方法的使用相對固定,了解即可。


4. 核心方法詳解
4.1 bind()
bind () 主要用來綁定本地端口號。
實例:
ChannelFuture future=serverBootstrap.bind(80);
future.addListener(new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) {
if (future.isSuccess()) {
System.out.println("端口綁定成功!");
} else {
System.err.println("端口綁定失敗!");
}
}
});
代碼升級,如果綁定的端口已經存在,則端口號遞增。當然,實際情況很少會去遞增端口號,一般都是上線之前確定端口號,否則客戶端不知道端口號,無法連接。
實例:
private static void bind(ServerBootstrap serverBootstrap, final int port) {
ChannelFuture future=serverBootstrap.bind(port);
future.addListener(new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) {
if (future.isSuccess()) {
System.out.println("端口[" + port + "]綁定成功!");
} else {
System.err.println("端口[" + port + "]綁定失敗!");
//遞歸重新綁定端口號
bind(serverBootstrap, port + 1);
}
}
});
}
4.2 attr()
attr () 方法可以給服務端的 channel,也就是 NioServerSocketChannel 指定一些自定義屬性,可以通過 channel.attr() 取出這個屬性。
實例:
//省略了其它模板代碼
serverBootstrap.attr(AttributeKey.newInstance("serverName"), "nettyServer")
總結,一般來說 attr () 運用得比較少,了解即可。
4.3 childAttr()
childAttr 可以給每一條連接指定自定義屬性,可以通過 channel.attr() 取出該屬性。
實例:
//省略了其它模板代碼
serverBootstrap.childAttr(AttributeKey.newInstance("clientKey"), "clientValue")
總結,常見的運用場景,客戶端登錄成功之后,給其對應的 Channel 綁定標識,下次只需要判斷該 Channel 是否有標識即可知道其是否已經登錄。
4.4 handler()
handler () 用于指定在服務端啟動過程中的一些邏輯。
實例:
//省略了其它模板代碼
serverBootstrap.handler(new ChannelInitializer<NioServerSocketChannel>() {
protected void initChannel(NioServerSocketChannel ch) {
System.out.println("服務端啟動中");
}
});
總結,可以在服務端啟動的過程中做一些初始化方面的工作,比如,讀取數據庫的配置數據放到緩存當中,這個作為了解即可。
4.5 childHandler()
childHandler () 用于指定處理新連接數據的讀寫處理邏輯。
實例:
//省略了其它模板代碼
serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
protected void initChannel(NioSocketChannel ch) {
//責任鏈,指定自定義處理業務的 Handler
ch.pipeline().addLast(new NettyServerHandler());
}
});
總結,這個是核心,主要管理業務邏輯處理雙向鏈表,后面會具體講解
4.6 option()
option () 給服務端 channel 設置一些屬性,最常見的就是 so_backlog。
實例:
//省略了其它模板代碼
serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024)
表示系統用于臨時存放已完成三次握手的請求的隊列的最大長度,如果連接建立頻繁,服務器處理創建新連接較慢,可以適當調大這個參數。其實,客戶端請求在服務端也是排隊執行的,服務端的兩大線程組分別監聽客戶端連接和處理客戶端連接,一旦并發量很高的時候,服務端處理不過來,則會把等待處理的請求放入到臨時隊列里面,這個跟 Java 線程池的思想是一樣的。
4.7 childOption()
childOption () 給每條連接設置一些 TCP 底層相關的屬性。
實例:
//省略了其它模板代碼
serverBootstrap
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
代碼說明:
- ChannelOption.SO_KEEPALIVE 表示是否開啟 TCP 底層心跳機制,true 未開啟;
- ChannelOption.TCP_NODELAY 表示是否開啟 Nagle 算法,true 表示關閉,false 表示開啟,通俗地說,如果要求高實時性,有數據發送時就馬上發送,就關閉,如果需要減少發送次數減少網絡交互,就開啟。
5. 小結
本節學習的核心知識點掌握,具體如下:
- 四個核心流程,分別是①設置線程組;②設置 IO 模型;③指定連接讀寫處理邏輯;④綁定端口號;
- 核心方法的使用場景,重點掌握①bind ();②childAttr ();③childHandler ();④childOption () 的使用。
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。