步驟 1:建立 serverbootstrap 例項。serverbootstrap 是 netty 服務端的
啟動輔助類,它提供了一系列的方法用於設定服務端啟動相關的引數。
步 驟 2: 設 置 並 綁 定 reactor 線 程 池。netty 的 reactor 線 程 池 是
eventloopgroup,它實際就是 eventloop 的陣列。eventloop 的職責是處理所有註冊到本執行緒多路復用器 selector 上的 channel,selector 的輪詢操作由繫結的 eventloop 執行緒 run 方法驅動,在乙個迴圈體內迴圈執行。
步 驟 3: 設 置 並 綁 定 服 務 端 channel。 作 為 nio 服 務 端, 需 要 創 建serversocketchannel,netty 對 原 生 的 nio 類 庫 進 行 了 封 裝, 對 應 實 現 是nioserversocketchannel。
步驟 4:鏈路建立的時候建立並初始化 channelpipeline。channelpipeline
並不是 nio 服務端必需的,它本質就是乙個負責處理網路事件的職責鏈,負責管理和執行 channelhandler。
步驟 5:初始化 channelpipeline 完成之後,新增並設定 channelhandler。
channelhandler 是 netty 提 供 給 用 戶 定 制 和 擴 展 的 關 鍵 接 口。
步驟 6:繫結並啟動監聽埠。
步驟 7:selector 輪詢。
步 驟 8: 當 輪 詢 到 準 備 就 緒 的 channel 之 後, 就 由 reactor 線
程 nioeventloop 執 行 channelpipeline 的 相 應 方 法, 最 終 調 度 並 執 行channelhandler。
步 驟 9: 執 行 netty 系 統 channelhandler 和 用 戶 添 加 定 制 的
所有的 netty 伺服器都需要以下兩部分。
至少乙個 channelhandler—該元件實現了伺服器對從客戶端接收的資料的處理,即它的業務邏輯。
引導—這是配置伺服器的啟動**。至少,它會將伺服器繫結到它要監聽連線請求的埠上。
echo 客戶端和伺服器之間的互動是非常簡單的;在客戶端建立乙個連線之後,它會向伺服器傳送乙個或多個訊息,反過來,伺服器又會將每個訊息回送給客戶端。雖然它本身看起來好像用處不大,但它充分地體現了客戶端/伺服器系統中典型的請求-響應互動模式。
1.channelhandler 和業務邏輯
簡單設計乙個echoserverhandler,它需要實現 channelinboundhandler 介面,用 來定義響應入站事件的方法。這個簡單的應用程式只需要用到少量的這些方法,所以繼承 channelinboundhandleradapter 類也就足夠了,它提供了 channelinboundhandler 的預設實現。
除了 channelinboundhandleradapter 之外,還有很多需要學習的 channelhandler 的子型別和實現。
針對不同型別的事件來呼叫 channelhandler;
應用程式通過實現或者擴充套件 channelhandler 來掛鉤到事件的生命週期,並且提供自定義的應用程式邏輯;
在架構上,channelhandler 有助於保持業務邏輯與網路處理**的分離。這簡化了開發過程,因為**必須不斷地演化以響應不斷變化的需求。
針對channelinboundhandleradapter 我們感興趣的方法是:
channelread()—對於每個傳入的訊息都要呼叫; channelreadcomplete()—通知channelinboundhandler最後一次對channelread()的呼叫是當前批量讀取中的最後一條訊息; exceptioncaught()—在讀取操作期間,有異常丟擲時會呼叫。
**如下:
@sharable
//標示乙個channelhandler 可以被多個 channel 安全地共享
public
class
echoserverhandler
extends
channelinboundhandleradapter
@override
public
void
channelreadcomplete
(channelhandlercontext ctx)
throws exception
@override
public
void
exceptioncaught
(channelhandlercontext ctx, throwable cause)
throws exception
}
2.引導伺服器伺服器本身的過程了,具體涉及以下內容:
繫結到伺服器將在其上監聽並接受傳入連線請求的埠;
配置 channel,以將有關的入站訊息通知給 echoserverhandler 例項。
public
class
echoserver
public
void
start()
throws interruptedexception })
; channelfuture f = b.
bind()
.sync()
;//非同步地繫結伺服器;呼叫 sync()方法阻塞等待直到繫結完成
f.channel()
.closefuture()
.sync()
;//獲取 channel 的closefuture,並且阻塞當前執行緒直到完成
group.
shutdowngracefully()
.sync()
;//關閉eventloopgroup ,釋放所有的資源
}public
static
void
main
(string[
] args)
throws interruptedexception
}
總結:建立了乙個 serverbootstrap 例項。因為你正在使用的是 nio 傳輸,所以你指定了 nioeventloopgroup 來接受和處理新的連線,並且將 channel 的型別指定為 nioserversocketchannel 。在此之後,你將本地位址設定為乙個具有選定埠的 inetsocketaddress 。伺服器將繫結到這個位址以監聽新的連線請求。使用了乙個特殊的類——channelinitializer。這是關鍵。當乙個新的連線被接受時,乙個新的子 channel 將會被建立,而 channelinitializer 將會把乙個你的echoserverhandler 的例項新增到該 channel 的 channelpipeline 中。正如我們之前所解釋的,這個 channelhandler 將會收到有關入站訊息的通知。
接下來你繫結了伺服器 ,並等待繫結完成。(對 sync()方法的呼叫將導致當前 thread阻塞,一直到繫結操作完成為止)。在 處,該應用程式將會阻塞等待直到伺服器的 channel關閉(因為你在 channel 的 closefuture 上呼叫了 sync()方法)。然後,你將可以關閉eventloopgroup,並釋放所有的資源,包括所有被建立的執行緒 。
回顧一下剛完成的伺服器實現中的重要步驟。下面這些是伺服器的主要
**元件:
echoserverhandler 實現了業務邏輯;
main()方法引導了伺服器;
引導過程中所需要的步驟如下:
建立乙個 serverbootstrap 的例項以引導和繫結伺服器;
建立並分配乙個 nioeventloopgroup 例項以進行事件的處理,如接受新連線以及讀/寫資料;
指定伺服器繫結的本地的 inetsocketaddress;
使用乙個 echoserverhandler 的例項初始化每乙個新的 channel;
呼叫 serverbootstrap.bind()方法以繫結伺服器。
至此,服務端簡單實現完成,在下一節中,將**對應的客戶端應用程式的**。
《網路程式設計》I O 模型
在分析 i o 模型之前,首先了解 同步 i o 和 非同步 i o 的基本概念 同步 i o 程序呼叫 i o 操作函式時,在 i o 操作函式返回之前,該程序會被掛起 即阻塞 直到 i o 操作完成後返回 非同步 i o 程序呼叫 i o 操作函式時,在 i o 操作函式返回之前,該程序不會被掛...
Linux網路程式設計(三) IO非阻塞操作
io非阻塞操作 sock的方法不一定非得是阻塞的,也可以非阻塞的操作。有兩種方法分別為設定fcntl 和設定相應函式的引數。服務端 include include include include include include include include define bufsize 128 i...
網路程式設計之IO模型 非同步IO
linux下的asynchronous io其實用得不多,從核心2.6版本才開始引入。先看一下它的流程 使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何bl...