日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《netty入门与实战》笔记-02:服务端启动流程

發布時間:2023/11/29 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《netty入门与实战》笔记-02:服务端启动流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

1.服務端啟動流程

這一小節,我們來學習一下如何使用 Netty 來啟動一個服務端應用程序,以下是服務端啟動的一個非常精簡的 Demo:

NettyServer.java

public class NettyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup = new NioEventLoopGroup();NioEventLoopGroup workerGroup = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<NioSocketChannel>() {protected void initChannel(NioSocketChannel ch) {}});serverBootstrap.bind(8000);} }
  • 首先看到,我們創建了兩個NioEventLoopGroup,這兩個對象可以看做是傳統IO編程模型的兩大線程組,bossGroup表示監聽端口,accept 新連接的線程組,workerGroup表示處理每一條連接的數據讀寫的線程組。用生活中的例子來講就是,一個工廠要運作,必然要有一個老板負責從外面接活,然后有很多員工,負責具體干活,老板就是bossGroup,員工們就是workerGroup,bossGroup接收完連接,扔給workerGroup去處理。
  • 接下來 我們創建了一個引導類 ServerBootstrap,這個類將引導我們進行服務端的啟動工作,直接new出來開搞。
  • 我們通過.group(bossGroup, workerGroup)給引導類配置兩大線程組,這個引導類的線程模型也就定型了。
  • 然后,我們指定我們服務端的 IO 模型為NIO,我們通過.channel(NioServerSocketChannel.class)來指定 IO 模型,當然,這里也有其他的選擇,如果你想指定 IO 模型為 BIO,那么這里配置上OioServerSocketChannel.class類型即可,當然通常我們也不會這么做,因為Netty的優勢就在于NIO。
  • 接著,我們調用childHandler()方法,給這個引導類創建一個ChannelInitializer,這里主要就是定義后續每條連接的數據讀寫,業務處理邏輯,不理解沒關系,在后面我們會詳細分析。ChannelInitializer這個類中,我們注意到有一個泛型參數NioSocketChannel,這個類呢,就是 Netty 對 NIO 類型的連接的抽象,而我們前面NioServerSocketChannel也是對 NIO 類型的連接的抽象,NioServerSocketChannel和NioSocketChannel的概念可以和 BIO 編程模型中的ServerSocket以及Socket兩個概念對應上

我們的最小化參數配置到這里就完成了,我們總結一下就是,要啟動一個Netty服務端,必須要指定三類屬性,分別是線程模型、IO 模型、連接讀寫處理邏輯,有了這三者,之后在調用bind(8000),我們就可以在本地綁定一個 8000 端口啟動起來,以上這段代碼讀者可以直接拷貝到你的 IDE 中運行。

2.自動綁定遞增端口

在上面代碼中我們綁定了 8000 端口,接下來我們實現一個稍微復雜一點的邏輯,我們指定一個起始端口號,比如 1000,然后呢,我們從1000號端口往上找一個端口,直到這個端口能夠綁定成功,比如 1000 端口不可用,我們就嘗試綁定 1001,然后 1002,依次類推。

serverBootstrap.bind(8000);這個方法呢,它是一個異步的方法,調用之后是立即返回的,他的返回值是一個ChannelFuture,我們可以給這個ChannelFuture添加一個監聽器GenericFutureListener,然后我們在GenericFutureListener的operationComplete方法里面,我們可以監聽端口是否綁定成功,接下來是監測端口是否綁定成功的代碼片段

serverBootstrap.bind(8000).addListener(new GenericFutureListener<Future<? super Void>>() {public void operationComplete(Future<? super Void> future) {if (future.isSuccess()) {System.out.println("端口綁定成功!");} else {System.err.println("端口綁定失敗!");}} });

我們接下來從 1000 端口號,開始往上找端口號,直到端口綁定成功,我們要做的就是在 if (future.isSuccess())的else邏輯里面重新綁定一個遞增的端口號,接下來,我們把這段綁定邏輯抽取出一個bind方法

private static void bind(final ServerBootstrap serverBootstrap, final int port) {serverBootstrap.bind(port).addListener(new GenericFutureListener<Future<? super Void>>() {public void operationComplete(Future<? super Void> future) {if (future.isSuccess()) {System.out.println("端口[" + port + "]綁定成功!");} else {System.err.println("端口[" + port + "]綁定失敗!");bind(serverBootstrap, port + 1);}}}); }

然后呢,以上代碼中最關鍵的就是在端口綁定失敗之后,重新調用自身方法,并且把端口號加一,然后,在我們的主流程里面,我們就可以直接調用

bind(serverBootstrap, 1000)

端口成功綁定了在1024,從 1000 開始到 1023,端口均綁定失敗了,這是因為在我的 MAC 系統下,1023 以下的端口號都是被系統保留了,需要 ROOT 權限才能綁定。

以上就是自動綁定遞增端口的邏輯,接下來,我們來一起學習一下,服務端啟動,我們的引導類ServerBootstrap除了指定線程模型,IO 模型,連接讀寫處理邏輯之外,他還可以干哪些事情?

3.服務端啟動其他方法

handler() 方法

serverBootstrap.handler(new ChannelInitializer<NioServerSocketChannel>() {protected void initChannel(NioServerSocketChannel ch) {System.out.println("服務端啟動中");} })

handler()方法呢,可以和我們前面分析的childHandler()方法對應起來,childHandler()用于指定處理新連接數據的讀寫處理邏輯,handler()用于指定在服務端啟動過程中的一些邏輯,通常情況下呢,我們用不著這個方法。

attr() 方法

serverBootstrap.attr(AttributeKey.newInstance("serverName"), "nettyServer")

attr()方法可以給服務端的 channel,也就是NioServerSocketChannel指定一些自定義屬性,然后我們可以通過channel.attr()取出這個屬性,比如,上面的代碼我們指定我們服務端channel的一個serverName屬性,屬性值為nettyServer,其實說白了就是給NioServerSocketChannel維護一個map而已,通常情況下,我們也用不上這個方法。

那么,當然,除了可以給服務端 channel NioServerSocketChannel指定一些自定義屬性之外,我們還可以給每一條連接指定自定義屬性

childAttr() 方法

serverBootstrap.childAttr(AttributeKey.newInstance("clientKey"), "clientValue")

上面的childAttr可以給每一條連接指定自定義屬性,然后后續我們可以通過channel.attr()取出該屬性。

childOption() 方法

serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true).childOption(ChannelOption.TCP_NODELAY, true)

childOption()可以給每條連接設置一些TCP底層相關的屬性,比如上面,我們設置了兩種TCP屬性,其中

  • ChannelOption.SO_KEEPALIVE表示是否開啟TCP底層心跳機制,true為開啟
  • ChannelOption.TCP_NODELAY表示是否開始Nagle算法,true表示關閉,false表示開啟,通俗地說,如果要求高實時性,有數據發送時就馬上發送,就關閉,如果需要減少發送次數減少網絡交互,就開啟。

其他的參數這里就不一一講解,有興趣的同學可以去這個類里面自行研究。

option() 方法

除了給每個連接設置這一系列屬性之外,我們還可以給服務端channel設置一些屬性,最常見的就是so_backlog,如下設置

serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024)

表示系統用于臨時存放已完成三次握手的請求的隊列的最大長度,如果連接建立頻繁,服務器處理創建新連接較慢,可以適當調大這個參數

4.總結

  • 本文中,我們首先學習了 Netty 服務端啟動的流程,一句話來說就是:創建一個引導類,然后給他指定線程模型,IO模型,連接讀寫處理邏輯,綁定端口之后,服務端就啟動起來了。
  • 然后,我們學習到 bind 方法是異步的,我們可以通過這個異步機制來實現端口遞增綁定。
  • 最后呢,我們討論了 Netty 服務端啟動額外的參數,主要包括給服務端 Channel 或者客戶端 Channel 設置屬性值,設置底層 TCP 參數。

以上內容來源于掘金小冊《Netty 入門與實戰:仿寫微信 IM 即時通訊系統》,若想獲得更多,更詳細的內容,請用微信掃碼訂閱:

轉載于:https://my.oschina.net/funcy/blog/2242215

總結

以上是生活随笔為你收集整理的《netty入门与实战》笔记-02:服务端启动流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。