Netty怎麼保持長連接?

很多個客戶端同時請求到netty服務端,在處理完的時候返迴響應結果給客戶端,服務這邊是怎麼征對某個具體的客戶端來寫這個結果的呢,應該也就是服務端要實現長連接的意思吧嗎


簡單一點的話,連接成功後客戶端可以發起一個類似註冊初始化的請求,伺服器端可以將Channel和客戶端的標示(設備ID或者玩家ID這類唯一性的東西)存儲在MAP中,然後在後續業務中根據標示就可以獲取到對應的Channel進行writeAndFlush。

即有客戶端連接、斷開連接時需維護這個MAP


1. 直接獲取socket值就可以了,remoteAddress 一般是唯一的

2. 直接保存整個ctx.channel,然後在inboundChannelhandler里對數據發送的ctx進行比對

3. 如果需要禁止多重連接,可以從remoteAddress裡面抓出一個IP地址出來,同一個IP地址在管理隊列里只允許存在一個socket連接

4. netty的核心不是並發計算,而是為了解決並發IO的效率問題,不要嘗試在netty的框架裡面做長連接的並發運算,用一個獨立的threadPool+futurePromise做管理。


你需要使用IdelStateHandler,書中有記錄。在過段時間後給客戶端發送一個KeepAlive的應用層消息,如果發送失敗了則關閉該連接。

您可以購買我翻譯的《Netty實戰》這本書。

如何評價《Netty實戰》這本書? - 知乎

京東預售鏈接(優先發貨):《Netty實戰》([美]諾曼·毛瑞爾(Norman Maurer),馬文·艾倫·沃爾夫泰爾(Marvin Allen Wolfthal))


傳統的阻塞socket通信是這樣的...

當客戶端要與服務端通信,客戶端首先要創建一個 Socket 實例,操作系統將為這個 Socket 實例分配一個沒有被使用的本地埠號,並創建一個包含本地和遠程地址和埠號的套接字數據結構,這個數據結構將一直保存在系統中直到這個連接關閉。當然這之前有一些操作,比如三次握手...

服務端將創建一個 ServerSocket ,操作系統也會為 ServerSocket 實例創建一個底層數據結構,這個數據結構中包含指定監聽的埠號和包含監聽地址的通配符,通常情況下都是「*」即監聽所有地址。之後當調用 accept() 方法時,將進入阻塞狀態,等待客戶端的請求。當一個新的請求到來時,將為這個連接創建一個新的套接字數據結構,該套接字數據的信息包含的地址和埠信息正是請求源地址和埠。這個新創建的數據結構將會關聯到 ServerSocket 實例的一個數據結構列表中,所以 ServerSocket 所關聯的列表中每個數據結構,都代表與一個客戶端的建立的 TCP 連接。

所以無論io模型怎麼變,netty服務端肯定是維護一個客戶端連接的數據結構列表...


正好在查這個資料,寫幾句話作為備忘。

首先建立一個映射關係是必須的。

其次客戶端肯定有標示,然後伺服器端區分的方式如下:

  • 如果Netty的版本是4.1、5(5已經被廢棄了),那麼可以用

Channel.id()

來區分,結合了MAC地址,當前PID,時間戳,哈希等多種信息。甚至可以作為全局唯一ID。

  • 如果Netty是4.0版本,那麼只能使用

    Channel.toString()

    或者使用

    hashCode(), remoteAddress(), and localAddress()

    計算出一個ID。

但是這種方式需要特別注意,因為channel在inactive的狀態,有些值是會改變的。


比如是http的話,客戶端根據url區分不同邏輯,netty接收到http獲取url,和方法get,post等,根據這些自定義路由類,將不同url路由到指定方法去執行,每個方法新建一個response,就可以回復了


推薦閱讀:

在集群中部署多個伺服器如何解決SESSION問題?
一個Web應用(比如網站)是如何部署在多個web伺服器上的?
創建一個應用伺服器,請大神提下建議?真實需求
魔獸世界例行維護究竟是在做什麼?

TAG:程序員 | 伺服器架構 | 後台開發 | Netty |