總體概述
類關(guān)系
給ServerBootstrap配置兩個(gè)EventLoopGroup,一個(gè)建立連接,一個(gè)處理網(wǎng)絡(luò)io。
EventLoopGroup給EventLoop分配線程。
在 Netty 中,EventLoop 通過(guò)不斷輪詢 Selector 來(lái)檢測(cè) Channel 上發(fā)生的事件,當(dāng) Channel 上的事件到達(dá)時(shí),EventLoop 會(huì)將事件傳入 相應(yīng)的Channel 的成員變量 ChannelPipeline 中,經(jīng)過(guò)所有ChannelHandler 來(lái)處理這些事件。
執(zhí)行流程
當(dāng)一個(gè)事件傳入時(shí),會(huì)判斷是連接事件還是其他事件,如果是連接事件交給eventloopgroup中的建立連接的eventloop,其中的nioserverchannel會(huì)處理連接事件,如果是其他事件,那么會(huì)交給處理網(wǎng)絡(luò)io的eventloop中的channel,eventloop輪詢發(fā)現(xiàn)有channel有事件需要執(zhí)行,那么就在這個(gè)eventloop線程中調(diào)用channel的channelpipeline,執(zhí)行相應(yīng)的channelhander。
其中:eventloopgroup可以指定eventloop的數(shù)量,eventloopgroup就像線程池一樣,會(huì)負(fù)載均衡地分配建立連接的channel給不同的eventloop。
Netty的NIO的常用概念
ServerBootstrap
ServerBootstrap 是一個(gè)用于幫助配置和啟動(dòng)服務(wù)器的類。它是Netty中用于創(chuàng)建服務(wù)器端應(yīng)用程序的主要入口點(diǎn)
Channel
在計(jì)算機(jī)網(wǎng)絡(luò)編程中,Channel(通道) 是一種抽象概念,代表著數(shù)據(jù)在源和目標(biāo)之間的連接。通道是數(shù)據(jù)傳輸?shù)耐?,通道的兩端可以是網(wǎng)絡(luò)連接、文件、套接字等。
Channel類型
- 文件通道 (FileChannel): 用于對(duì)文件進(jìn)行讀寫(xiě)操作。
- 套接字通道 (SocketChannel, ServerSocketChannel, DatagramChannel): 用于進(jìn)行網(wǎng)絡(luò)通信,這些通道是基于 Java NIO 提供的 SelectableChannel 的實(shí)現(xiàn)。它們通常通過(guò) EventLoop、ChannelPipeline 和自定義的處理器來(lái)實(shí)現(xiàn)異步和事件驅(qū)動(dòng)的網(wǎng)絡(luò)編程。
SocketChannel 是用于 TCP 客戶端通信的通道。
它可以連接到遠(yuǎn)程服務(wù)器,并進(jìn)行雙向通信。
SocketChannel 支持阻塞和非阻塞的模式。
ServerSocketChannel 是用于 TCP 服務(wù)器通信的通道。
它監(jiān)聽(tīng)客戶端的連接請(qǐng)求,并創(chuàng)建一個(gè)新的 SocketChannel 用于與客戶端通信。
ServerSocketChannel 也支持阻塞和非阻塞的模式。
DatagramChannel 是用于 UDP 通信的通道。
UDP 是面向消息的,DatagramChannel 支持無(wú)連接的數(shù)據(jù)報(bào)傳輸。
DatagramChannel 與 SocketChannel 相比更輕量,適用于不需要可靠性傳輸?shù)膱?chǎng)景。
- 管道 (Pipe.SinkChannel, Pipe.SourceChannel): 用于在兩個(gè)線程之間進(jìn)行通信。
通道(Channel)和流(Stream)有一些相似之處,但也有一些關(guān)鍵的區(qū)別。
相似之處
數(shù)據(jù)傳輸: 通道和流都用于在程序和數(shù)據(jù)源/目的地之間進(jìn)行數(shù)據(jù)傳輸。
字節(jié)流和字符流: 通道和流都可以用于處理字節(jié)數(shù)據(jù)(字節(jié)流)和字符數(shù)據(jù)(字符流)。
區(qū)別
阻塞非阻塞
通道: 通道通常是非阻塞的,可以使用選擇器(Selector)來(lái)實(shí)現(xiàn)多路復(fù)用,從而監(jiān)控多個(gè)通道的狀態(tài)。
流: 流通常是阻塞的,即在讀寫(xiě)操作時(shí),如果沒(méi)有數(shù)據(jù)可讀或沒(méi)有足夠的空間可寫(xiě),程序會(huì)阻塞等待。
雙向性
通道: 通道是雙向的,可以支持讀和寫(xiě)操作。例如,文件通道 (FileChannel) 可以同時(shí)支持讀取和寫(xiě)入文件。
流: 流通常是單向的,即要么是輸入流(從數(shù)據(jù)源讀取數(shù)據(jù)),要么是輸出流(向數(shù)據(jù)源寫(xiě)入數(shù)據(jù))。需要使用兩個(gè)流才能實(shí)現(xiàn)雙向傳輸。
底層實(shí)現(xiàn)
通道: 通道通常直接映射到操作系統(tǒng)的底層 I/O 操作,因此性能可能更好。在 Java NIO 中,通道與 Selector 搭配使用,可以實(shí)現(xiàn)非阻塞 I/O。
流: 流通常是在通道的基礎(chǔ)上建立的高級(jí)抽象,提供了更高層次的 API。在 Java IO 中,流是基于字節(jié)或字符的 I/O 操作。
直接緩沖區(qū)
在 Java NIO 中,通道(Channel)支持直接緩沖區(qū)(DirectBuffer),這使得數(shù)據(jù)可以直接從內(nèi)存中的緩沖區(qū)傳輸?shù)酵ǖ?,或者從通道直接傳輸?shù)絻?nèi)存中的緩沖區(qū),而不需要中間步驟。
通道: 通道支持直接緩沖區(qū),允許將數(shù)據(jù)直接從內(nèi)存中的緩沖區(qū)傳輸?shù)酵ǖ?,而不需要中間步驟。
流: 流通常不支持直接緩沖區(qū),需要通過(guò)中間的數(shù)組或緩沖區(qū)來(lái)進(jìn)行數(shù)據(jù)傳輸。
通常有兩種類型的緩沖區(qū):堆緩沖區(qū)(Heap Buffer)和直接緩沖區(qū)(Direct Buffer)。
堆緩沖區(qū): 在堆上分配的緩沖區(qū),數(shù)據(jù)位于Java堆內(nèi)存中。這是默認(rèn)的緩沖區(qū)類型。
直接緩沖區(qū): 直接分配在操作系統(tǒng)的內(nèi)存中,而不是Java堆中。直接緩沖區(qū)可以通過(guò) ByteBuffer.allocateDirect() 方法來(lái)創(chuàng)建。
直接緩沖區(qū)的優(yōu)勢(shì)之一是可以通過(guò) FileChannel 的 transferTo() 和 transferFrom() 方法直接在通道之間傳輸數(shù)據(jù),而無(wú)需通過(guò)中間緩沖區(qū)。
當(dāng)使用非直接緩沖區(qū)(Heap Buffer)時(shí),通常的操作是先將數(shù)據(jù)從通道讀取到堆緩沖區(qū),然后再進(jìn)行其他操作。同樣,當(dāng)寫(xiě)入時(shí),數(shù)據(jù)也會(huì)從堆緩沖區(qū)寫(xiě)入到通道。
Channel內(nèi)部有成員變量unsafe和Pipeline,unsafe是Channel網(wǎng)絡(luò)io的底層實(shí)現(xiàn),ChannelPipeline 負(fù)責(zé)管理該 Channel 上的處理器鏈。
SelectionKey
簡(jiǎn)單源碼
public interface SelectionKey {
// 表示對(duì)讀事件感興趣
static final int OP_READ = 1;
// 表示對(duì)寫(xiě)事件感興趣
static final int OP_WRITE = 4;
// 表示對(duì)連接事件感興趣
static final int OP_CONNECT = 8;
// 表示對(duì)接受事件感興趣
static final int OP_ACCEPT = 16;
// 返回與此鍵關(guān)聯(lián)的通道
SelectableChannel channel();
// 返回選擇器
Selector selector();
// 返回表示感興趣的事件的操作集合
int interestOps();
// 設(shè)置感興趣的事件的操作集合
SelectionKey interestOps(int ops);
// 返回表示已準(zhǔn)備就緒的操作的操作集合
int readyOps();
。。。。。。。
}
ChannelPipline
ChannelPipline是ChannelHandler的容器,維護(hù)了一個(gè)Handler的鏈表和迭代器。
當(dāng)事件發(fā)生時(shí),在eventloop的中它會(huì)被傳遞給ChannelPipeline,然后從頭到尾依次經(jīng)過(guò)每個(gè)ChannelHandler。
使用ServerBootstrap啟動(dòng)服務(wù)器netty會(huì)自動(dòng)為每個(gè)Channel創(chuàng)建一個(gè)獨(dú)立的pipepline,我們只要將想用的ChannelHandle加入即可。
ChannelHandler
事務(wù)的執(zhí)行是通過(guò)channelpipeline,連接,讀寫(xiě)等網(wǎng)絡(luò)io操作是由channelpipeline的Handler執(zhí)行(Handler中調(diào)用unsafe的方法)。
Eventloop
Eventloop作為NIO框架的Reactor線程,其中有一個(gè)Select的成員變量,用來(lái)實(shí)現(xiàn)多路復(fù)用。
Channel需要注冊(cè)到EventLoop的多路復(fù)用器上,EventLoop本質(zhì)上就是處理網(wǎng)絡(luò)讀寫(xiě)任務(wù)的Reactor線程,在Neety中,它還可以用力啊處理定時(shí)任務(wù)和用戶自定義NioTask任務(wù)。
Eventloop的run方法是其核心,偽代碼:
public void run() {
while (true) {
try {
// 阻塞直到有事件發(fā)生
int readyChannels = selector.select();
// 處理所有已經(jīng)就緒的事件
if (readyChannels > 0) {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
for (SelectionKey key : selectedKeys) {
if (key.isAcceptable()) {
// 處理連接事件
// 處理連接事件的邏輯
} else if (key.isReadable()) {
// 處理讀事件
// 處理讀事件的邏輯
} else if (key.isWritable()) {
// 處理寫(xiě)事件
// 處理寫(xiě)事件的邏輯
}
// 可以處理更多類型的事件,根據(jù)實(shí)際需要擴(kuò)展
}
selectedKeys.clear();
}
// 處理任務(wù)隊(duì)列中的任務(wù)
while (!tasks.isEmpty()) {
Runnable task = tasks.poll();
task.run();
}
} catch (IOException e) {
// 處理異常情況
e.printStackTrace();
}
}
EventGroup
EventLoopGroup 負(fù)責(zé)管理一組 EventLoop 實(shí)例,每個(gè) EventLoop 實(shí)例與一個(gè)線程相關(guān)聯(lián)。
EventLoopGroup 提供了 shutdownGracefully() 方法,用于優(yōu)雅地關(guān)閉所有關(guān)聯(lián)的 EventLoop。
服務(wù)端啟動(dòng)時(shí)候,創(chuàng)建了兩個(gè)NioEventLoopGroup,他們是兩個(gè)獨(dú)立的Reactor線程池,一個(gè)用來(lái)接收客戶端的TCP連接,另一個(gè)用來(lái)處理IO相關(guān)的讀寫(xiě)操作,或者執(zhí)行系統(tǒng)Task,定時(shí)任務(wù)Task等。
接收客戶端請(qǐng)求的線程池職責(zé)
- 接收客戶端的TCP連接,初始化Channel參數(shù)。
- 將鏈路狀態(tài)變更事件通知給ChannelPipeline。
處理IO操作的線程池的職責(zé)
- 異步讀取通信數(shù)據(jù)包,發(fā)送讀事件給ChannelPipeline;
- 異步發(fā)送消息,通過(guò)發(fā)送讀事件給ChannelPipeline。
- 執(zhí)行系統(tǒng)Task和定時(shí)Task;
Promise和Future
Promise 是 Future 的擴(kuò)展,它繼承了 Future 接口。它們都代表了一個(gè)尚未完成的操作,可以用于異步操作的結(jié)果通知和處理。
區(qū)別:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-823033.html
可寫(xiě)性: Future 是只讀的,一旦創(chuàng)建就不能被修改。而 Promise 是可寫(xiě)的,可以通過(guò)它來(lái)設(shè)置操作的結(jié)果。
操作結(jié)果的設(shè)置: 在使用 Future 時(shí),你只能等待其完成,而不能主動(dòng)設(shè)置操作的結(jié)果。而在使用 Promise 時(shí),你可以主動(dòng)設(shè)置操作的結(jié)果,因此它提供了更靈活的控制。
用途: Future 通常用于表示一個(gè)異步操作的結(jié)果,而 Promise 用于表示一個(gè)異步操作的開(kāi)始和結(jié)果的產(chǎn)生。在很多情況下,你會(huì)首先創(chuàng)建一個(gè) Promise,然后將它轉(zhuǎn)化為一個(gè) Future 對(duì)象,傳遞給其他部分的代碼,使得它們可以等待異步操作的結(jié)果。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-823033.html
到了這里,關(guān)于NIO和netty的常用類的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!