摘要:客戶端客戶端啟動的常規代碼如下用于接收客戶端請求的線程池職責如下。注冊對應的網絡監聽狀態為到多路復用器。由多路復用器在現場中輪詢個,處理連接結果。具體服務端與客戶端如何通信,以及內存管理等方面的知識下一次再寫。
歡迎關注公眾號:【愛編程】
如果有需要后臺回復2019贈送1T的學習資料哦!!
本文是基于Netty4.1.36進行分析
服務端Netty服務端的啟動代碼基本都是如下:
private void start() throws Exception { final EchoServerHandler serverHandler = new EchoServerHandler(); /** * NioEventLoop并不是一個純粹的I/O線程,它除了負責I/O的讀寫之外 * 創建了兩個NioEventLoopGroup, * 它們實際是兩個獨立的Reactor線程池。 * 一個用于接收客戶端的TCP連接, * 另一個用于處理I/O相關的讀寫操作,或者執行系統Task、定時任務Task等。 */ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { //ServerBootstrap負責初始化netty服務器,并且開始監聽端口的socket請求 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, childGroup) .channel(NioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // 為監聽客戶端read/write事件的Channel添加用戶自定義的ChannelHandler socketChannel.pipeline().addLast(serverHandler); } }); ChannelFuture f = b.bind().sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully().sync(); childGroup.shutdownGracefully().sync(); } }
從上圖的代碼可以總結為以下幾個步驟:
1、創建ServerBootStrap實例
2、設置并綁定Reactor線程池:EventLoopGroup,EventLoop就是處理所有注冊到本線程的Selector上面的Channel
3、設置并綁定服務端的channel
4、5、創建處理網絡事件的ChannelPipeline和handler,網絡時間以流的形式在其中流轉,handler完成多數的功能定制:比如編解碼 SSl安全認證
6、綁定并啟動監聽端口
7、當輪訓到準備就緒的channel后,由Reactor線程:NioEventLoop執行pipline中的方法,最終調度并執行channelHandler
它就是主要引導啟動服務端,工作包括以下:
1.創建服務端Channel
2.初始化服務端Channel
3.將Channel注冊到selector
4.端口綁定
1.創建服務端Channel流程:
首先從用戶代碼的bind()其實就是AbstractBootstrap.bind(),然后通過反射工廠將用戶通過b.channel(NioServerSocketChannel.class)傳入的NioServerSocketChannel通過調用底層的jdk的SelectorProvider創建channel,同時也接著創建好對應的ChannelPipeline。
詳情可以參考下圖,自己去查看一下源碼:
主要工作如下:
1)設置的option緩存到NioServerSocketChannelConfig里
2)設置的attr設置到channel里
3)保存配置的childOptions,配置的childAttrs 到ServerBootstrapAcceptor里
4)往NioSocketChannel的pipeline中添加一個ServerBootstrapAcceptor
主要的核心源碼如下:
@Override void init(Channel channel) throws Exception { final Map, Object> options = options0(); synchronized (options) { setChannelOptions(channel, options, logger); } final Map , Object> attrs = attrs0(); synchronized (attrs) { for (Entry , Object> e: attrs.entrySet()) { @SuppressWarnings("unchecked") AttributeKey
小結:
總體如上面工作流程所述。
特別地建議:查看ServerBootstrapAcceptor源碼,你可以發現ServerBootstrapAcceptor在channelRead事件觸發的時候(也就有客戶端連接的時候),把childHandler加到childChannel Pipeline的末尾,設置childHandler的options和attrs,最后把childHandler注冊進childGroup
注冊過程如下圖
小結:
Channel 注冊過程所做的工作就是將 Channel 與對應的 EventLoop 關聯。
1).每個 Channel 都會關聯一個特定的 EventLoop, 并且這個 Channel 中的所有 IO 操作都是在這個 EventLoop 中執行的;
2).當關聯好 Channel 和 EventLoop 后, 會繼續調用底層的 Java NIO SocketChannel 的 register 方法, 將底層的 Java NIO SocketChannel 注冊到指定的 selector 中.
通過這兩步, 就完成了 Netty Channel 的注冊過程.
4.端口綁定端口綁定的源碼流程基本如下圖,詳情可以還是你自己讀一下源碼比較好點。
小結:
其實netty端口綁定是調用 jdk的javaChannel().bind(localAddress, config.getBacklog());進行綁定,然后TCP鏈路建立成功,Channel激活事件,通過channelPipeline進行傳播。
客戶端啟動的常規代碼如下:
private void start() throws Exception { /** * Netty用于接收客戶端請求的線程池職責如下。 * (1)接收客戶端TCP連接,初始化Channel參數; * (2)將鏈路狀態變更事件通知給ChannelPipeline */ EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .remoteAddress(new InetSocketAddress(host,port)) .handler(new ChannelInitializer流程:() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new EchoClientHandler()); } }); //綁定端口 ChannelFuture f = b.connect().sync(); f.channel().closeFuture().sync(); } catch (Exception e) { group.shutdownGracefully().sync(); } }
1.用戶線程創建Bootstrap實例,通過API設置創建客戶端相關的參數,異步發起客戶端連接。
2.創建處理客戶端連接、I/O讀寫的Reactor線程組NioEventLoopGroup,默認為CPU內核數的2倍。
3.通過Bootstrap的ChannelFactory和用戶指定的Channel類型創建用于客戶端NioSocketChannel,它的功能類似于JDK NIO類庫提供的SocketChannel
4.創建默認的Channel Handler Pipeline,用于調度和執行網路事件。
5.異步發起TCP連接,判斷連接是否成功。如果成功,則直接將NioSocketChannel注冊到多路復用器上,監聽讀操作位,用于數據包讀取和消息發送,如果沒有立即連接成功,則注冊連接監聽為到多路復用器,等待連接結果。
6.注冊對應的網絡監聽狀態為到多路復用器。
7.由多路復用器在I/O現場中輪詢個Channel,處理連接結果。
8.如果連接成功,設置Future結果,發送連接成功事件,觸發ChannelPipeline執行。
9.由ChannelPipeline調度執行系統和用戶的ChannelHandler,執行邏輯。
小結:
客戶端是如何發起 TCP 連接的?
如下圖:
特別提醒:
在AbstractChannelHandlerContext.connect()#findContextOutbound這步操作是返回的結果next其實是頭節點,也就是說在下一步next.invokeConnect()這里的next就是頭節點,所以最終是調用HeadContext .connect()
本文主要講述netty服務端和客戶端的簡單工作流程。
具體服務端與客戶端如何通信,以及內存管理等方面的知識下一次再寫。
如果對 Java、大數據感興趣請長按二維碼關注一波,我會努力帶給你們價值。覺得對你哪怕有一丁點幫助的請幫忙點個贊或者轉發哦。
關注公眾號【愛編碼】,回復2019有相關資料哦。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74769.html
摘要:它使用了事件通知以確定在一組非阻塞套接字中有哪些已經就緒能夠進行相關的操作。目前,可以把看作是傳入入站或者傳出出站數據的載體。出站事件是未來將會觸發的某個動作的操作結果,這些動作包括打開或者關閉到遠程節點的連接將數據寫到或者沖刷到套接字。 netty的概念 定義 Netty 是一款異步的事件驅動的網絡應用程序框架,支持快速地開發可維護的高性能的面向協議的服務器和客戶端。我們可以很簡單的...
摘要:是一個面向字節流的協議,它是性質是流式的,所以它并沒有分段。可基于分隔符解決。編解碼的主要目的就是為了可以編碼成字節流用于在網絡中傳輸持久化存儲。 showImg(https://segmentfault.com/img/remote/1460000015895049); 前言 記得前段時間我們生產上的一個網關出現了故障。 這個網關邏輯非常簡單,就是接收客戶端的請求然后解析報文最后發送...
摘要:目錄源碼分析之番外篇的前生今世的前生今世之一簡介的前生今世之二小結的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環境搭建源碼分析之一揭開神秘的紅蓋頭源碼分析之一揭開神秘的紅蓋頭客戶端源碼分析之一揭開神秘的紅蓋頭服務器 目錄 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NIO 的前生今世 之一 簡介 Java NIO 的前生今世 ...
摘要:我想這很好的解釋了中,僅僅一個都這么復雜,在單線程或者說串行的程序中,編程往往是很簡單的,說白了就是調用,調用,調用然后返回。 Netty源碼分析(三) 前提概要 這次停更很久了,原因是中途迷茫了一段時間,不過最近調整過來了。不過有點要說下,前幾天和業內某個大佬聊天,收獲很多,所以這篇博文和之前也會不太一樣,我們會先從如果是我自己去實現這個功能需要怎么做開始,然后去看netty源碼,與...
摘要:一證書本文只介紹版,其他系統只供參考生成證書下載并安裝未編譯編譯好在目錄下打開命令行,輸入在本目錄得到和文件生成服務端和客戶端私鑰命令行輸入密碼自己設定,好幾個密碼,別弄亂了就好,分不清的話都設成一樣的根據生成文件 一、證書 (本文只介紹windows版,其他系統只供參考) 1.生成ca證書 下載 openssl 并安裝 未編譯 編譯好 在openssl/bin目錄下打開命令行,輸入...
閱讀 1660·2021-11-23 10:07
閱讀 2653·2019-08-30 11:10
閱讀 2834·2019-08-29 17:08
閱讀 1778·2019-08-29 15:42
閱讀 3163·2019-08-29 12:57
閱讀 2396·2019-08-28 18:06
閱讀 3544·2019-08-27 10:56
閱讀 383·2019-08-26 11:33