Netty中包含的 Transport

2020-11-17 17:07 更新

雖然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

方法名稱描述
NIOio.netty.channel.socket.nio基于java.nio.channels的工具包,使用選擇器作為基礎(chǔ)的方法。
OIOio.netty.channel.socket.oio基于java.net的工具包,使用阻塞流。
Localio.netty.channel.local用來在虛擬機(jī)之間本地通信。
Embeddedio.netty.channel.embedded嵌入傳輸,它允許在沒有真正網(wǎng)絡(luò)的傳輸中使用 ChannelHandler,可以非常有用的來測(cè)試ChannelHandler的實(shí)現(xiàn)。

NIO-Nonblocking I/O

NIO傳輸是目前最常用的方式,它通過使用選擇器提供了完全異步的方式操作所有的 I/O,NIO 從Java 1.4才被提供。

NIO 中,我們可以注冊(cè)一個(gè)通道或獲得某個(gè)通道的改變的狀態(tài),通道狀態(tài)有下面幾種改變:

  • 一個(gè)新的 Channel 被接受并已準(zhǔn)備好
  • Channel 連接完成
  • Channel 中有數(shù)據(jù)并已準(zhǔn)備好讀取
  • Channel 發(fā)送數(shù)據(jù)出去

處理完改變的狀態(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

Figure%204

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è)阻塞傳輸。

OIO-Old blocking I/O

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

Figure%204

1.線程分配給 Socket

2.Socket 連接到遠(yuǎn)程

3.讀操作(可能會(huì)阻塞)

4.讀完成

5.處理可讀的字節(jié)

6.執(zhí)行提交到 socket 的其他任務(wù)

7.再次嘗試讀

同個(gè) JVM 內(nèi)的本地 Transport 通信

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í),要注意正確的用法。除此限制之外,它的使用是與其他的傳輸是相同的。

內(nèi)嵌 Transport

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。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)