W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
雖然Netty不能支持所有的傳輸協(xié)議,但是Netty自身是攜帶了一些傳輸協(xié)議的,這些Netty自帶的傳輸協(xié)議已經(jīng)能夠滿足我們的使用。Netty應(yīng)用程序的傳輸協(xié)議依賴的是底層協(xié)議,接下來我們學(xué)習(xí)的內(nèi)容就是Netty中包含的傳輸協(xié)議。
Netty中的傳輸方式有如下幾種:
Table 4.1 Provided transports
方法名稱 | 包 | 描述 |
---|---|---|
NIO | io.netty.channel.socket.nio | 基于java.nio.channels的工具包,使用選擇器作為基礎(chǔ)的方法。 |
OIO | io.netty.channel.socket.oio | 基于java.net的工具包,使用阻塞流。 |
Local | io.netty.channel.local | 用來在虛擬機(jī)之間本地通信。 |
Embedded | io.netty.channel.embedded | 嵌入傳輸,它允許在沒有真正網(wǎng)絡(luò)的傳輸中使用 ChannelHandler,可以非常有用的來測(cè)試ChannelHandler的實(shí)現(xiàn)。 |
NIO傳輸是目前最常用的方式,它通過使用選擇器提供了完全異步的方式操作所有的 I/O,NIO 從Java 1.4才被提供。
NIO 中,我們可以注冊(cè)一個(gè)通道或獲得某個(gè)通道的改變的狀態(tài),通道狀態(tài)有下面幾種改變:
處理完改變的狀態(tài)后需重新設(shè)置他們的狀態(tài),用一個(gè)線程來檢查是否有已準(zhǔn)備好的 Channel,如果有則執(zhí)行相關(guān)事件。在這里可能只同時(shí)一個(gè)注冊(cè)的事件而忽略其他的。選擇器所支持的操作在 SelectionKey 中定義,具體如下:
Table 4.2 Selection operation bit-set
方法名稱 | 描述 |
---|---|
OP_ACCEPT | 有新連接時(shí)得到通知 |
OP_CONNECT | 連接完成后得到通知 |
OP_READ | 準(zhǔn)備好讀取數(shù)據(jù)時(shí)得到通知 |
OP_WRITE | 寫入更多數(shù)據(jù)到通道時(shí)得到通知,大部分時(shí)間 |
這是可能的,但有時(shí) socket 緩沖區(qū)完全填滿了。這通常發(fā)生在你寫數(shù)據(jù)的速度太快了超過了遠(yuǎn)程節(jié)點(diǎn)的處理能力。
Figure 4.2 Selecting and Processing State Changes
1.新信道注冊(cè) WITH 選擇器
2.選擇處理的狀態(tài)變化的通知
3.以前注冊(cè)的通道
4.Selector.select()方法阻塞,直到新的狀態(tài)變化接收或配置的超時(shí) 已過
5.檢查是否有狀態(tài)變化
6.處理所有的狀態(tài)變化
7.在選擇器操作的同一個(gè)線程執(zhí)行其他任務(wù)
有一種功能,目前僅適用于 NIO 傳輸叫什么 “zero-file-copy (零文件拷貝)”,這使您能夠快速,高效地通過移動(dòng)數(shù)據(jù)到從文件系統(tǒng)傳輸內(nèi)容 網(wǎng)絡(luò)協(xié)議棧而無需復(fù)制從內(nèi)核空間到用戶空間。這可以使 FT P或 HTTP 協(xié)議有很大的不同。
然而,并非所有的操作系統(tǒng)都支持此功能。此外,你不能用它實(shí)現(xiàn)數(shù)據(jù)加密或壓縮文件系統(tǒng) - 僅支持文件的原生內(nèi)容。另一方面,傳送的文件原本已經(jīng)加密的是完全有效的。
接下來,我們將討論的是 OIO ,它提供了一個(gè)阻塞傳輸。
Netty 中,該 OIO 傳輸代表了一種妥協(xié)。它通過了 Netty 的通用 API 訪問但不是異步,而是構(gòu)建在 java.net 的阻塞實(shí)現(xiàn)上。任何人下面討論這一點(diǎn)可能會(huì)認(rèn)為,這個(gè)協(xié)議并沒有很大優(yōu)勢(shì)。但它確實(shí)有它有效的用途。
假設(shè)你需要的端口使用該做阻塞調(diào)用庫(kù)(例如 JDBC)。它可能不適合非阻塞。相反,你可以在短期內(nèi)使用 OIO 傳輸,后來移植到純異步的傳輸上。讓我們看看它是如何工作的。
在 java.net API,你通常有一個(gè)線程接受新的連接到達(dá)監(jiān)聽在ServerSocket,并創(chuàng)建一個(gè)新的線程來處理新的 Socket 。這是必需的,因?yàn)樵谝粋€(gè)特定的 socket的每個(gè) I/O 操作可能會(huì)阻塞在任何時(shí)間。在一個(gè)線程處理多個(gè) socket 易造成阻塞操作,一個(gè) socket 占用了所有的其他人。
鑒于此,你可能想知道 Netty 是如何用相同的 API 來支持 NIO 的異步傳輸。這里的 Netty 利用了 SO_TIMEOUT 標(biāo)志,可以設(shè)置在一個(gè) Socket。這 timeout 指定最大 毫秒 數(shù)量 用于等待 I/O 的操作完成。如果操作在指定的時(shí)間內(nèi)失敗,SocketTimeoutException 會(huì)被拋出。 Netty中捕獲該異常并繼續(xù)處理循環(huán)。在接下來的事件循環(huán)運(yùn)行,它再次嘗試。像 Netty 的異步架構(gòu)來支持 OIO 的話,這其實(shí)是唯一的辦法。當(dāng)SocketTimeoutException 拋出時(shí),執(zhí)行 stack trace。
Figure 4.3 OIO-Processing logic
1.線程分配給 Socket
2.Socket 連接到遠(yuǎn)程
3.讀操作(可能會(huì)阻塞)
4.讀完成
5.處理可讀的字節(jié)
6.執(zhí)行提交到 socket 的其他任務(wù)
7.再次嘗試讀
Netty 提供了“本地”傳輸,為運(yùn)行在同一個(gè) Java 虛擬機(jī)上的服務(wù)器和客戶之間提供異步通信。此傳輸支持所有的 Netty 常見的傳輸實(shí)現(xiàn)的 API。
在此傳輸中,與服務(wù)器 Channel 關(guān)聯(lián)的 SocketAddress 不是“綁定”到一個(gè)物理網(wǎng)絡(luò)地址中,而是在服務(wù)器是運(yùn)行時(shí)它被存儲(chǔ)在注冊(cè)表中,當(dāng) Channel 關(guān)閉時(shí)它會(huì)注銷。由于該傳輸不是“真正的”網(wǎng)絡(luò)通信,它不能與其他傳輸實(shí)現(xiàn)互操作。因此,客戶端是希望連接到使用本地傳輸?shù)牡姆?wù)器時(shí),要注意正確的用法。除此限制之外,它的使用是與其他的傳輸是相同的。
Netty中 還提供了可以嵌入 ChannelHandler 實(shí)例到其他的 ChannelHandler 的傳輸,使用它們就像輔助類,增加了靈活性的方法,使您可以與你的 ChannelHandler 互動(dòng)。
該嵌入技術(shù)通常用于測(cè)試 ChannelHandler 的實(shí)現(xiàn),但它也可用于將功能添加到現(xiàn)有的 ChannelHandler 而無需更改代碼。嵌入傳輸?shù)年P(guān)鍵是Channel 的實(shí)現(xiàn),稱為“EmbeddedChannel”。
在第10章中描述了使用 EmbeddedChannel 來測(cè)試 ChannelHandlers。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: