1. 程式人生 > 其它 >開源庫GameNetty—讓編寫Socket服務像HTTP一樣簡單

開源庫GameNetty—讓編寫Socket服務像HTTP一樣簡單

技術標籤:Nettyjavasocketnettytcp開源

在java領域,Netty已經成為編寫Socket服務的首選。稍有遺憾的是,相比Spring MVC,Netty的使用門檻還是比較高的;要用好Netty,必需掌握好多執行緒、Socket、底層位元組操作等技能,而且相關程式的除錯難度也比較大。
本人使用Netty從事遊戲服務開發近5年,不斷打磨底層網路框架,誕生了GameNetty這個工具庫,權當本人對這個領域一點微不足道的回饋吧。

原始碼地址:https://github.com/longhuihu/game-netty

GameNetty目前用於公司的多個專案,非常穩定。當然受限於使用場景,肯定還有很多不足之處,期望得到同行的批評指正。

一、用途

GameNetty是一個使用TCP協議的網路通訊開源庫,它內部使用了Netty(4.1.50),讓使用者不必深入理解Netty也能輕鬆地編寫TCP通訊程式。

功能特點:

  • 支援tcp通訊,遮蔽了Netty的複雜性,尤其是ByteBuf的使用;
  • 靈活的訊息格式,使用者可自由決定使用二進位制或文字訊息格式;
  • 支援訊息加密和壓縮,內建了RC4加密和GZIP壓縮功能,使用者可擴充套件;
  • 支援websocket;
  • 實現了Client—Proxy—Server(客戶端—遊戲閘道器—遊戲服)三層網路結構,在Proxy端做了大量效能優化;

一句話總結,使用GameNetty來構建TCP服務,就像使用Spring MVC構建基於HTTP服務一樣簡單

GameNetty最適用的場景是使用TCP或WebSocket的網路遊戲,它原本就是脫胎於遊戲專案;後續也廣泛用於服務程序之間的通訊,尤其當你的業務場景簡單,不想依賴額外的RPC,MQ框架時。總之,那些需要頻繁傳遞網路訊息的場景,GameNetty都可能派上用場。

二、概念

GameNetty內的概念儘量與Netty保持一致,比如,xxxAcceptor代表TCP監聽端,xxxConnector代表TCP連線的發起端,xxxChannel代表一條TCP連線(本質是Netty Channel的包裝器)。
xxxCodec代表編解碼器,訊息的編碼和解碼邏輯一般緊密關聯,所以GameNetty不再將它們分開。

GameNetty功能類大體被分成了Client和Proxy兩組,Client意指和客戶端相關,用來支援客戶端發起連線(Connector),伺服器監聽客戶端連線請求(Acceptor)。

Proxy意指代理伺服器,遊戲行業也經常稱為閘道器(Gate)伺服器,包括代理連線後端服務的Connector和後端接受連線的Acceptor。Proxy的存在直接支援了網路遊戲常見的Client—Proxy—Server三層網路結構。

如果客戶端直連伺服器,專案使用GameNetty的方式如下:

       -------------------------                     -------------------------
       |   ClientConnector     | <--ClientMessage--> |  ClientSocketAcceptor  | 
       | (ClientConnectChannel)|                     | (ClientAcceptedChannel)|
       ------------------------                      --------------------------
           Client Side                                      Server Side

如果採用Client—Proxy—Server結構,專案使用GameNetty的方式如下:

       -------------------------                     ------------------------          
       |   ClientConnector     | <--ClientMessage--> |   ClientSocketAcceptor |
       | (ClientConnectChannel)|                     | (ClientAcceptedChannel)|          
       ------------------------                      |                        |                    ------------------------
                                                     |       ProxyAcceptor    | <--ProxyMessage--> |    ProxyAcceptor      | 
                                                     | (ProxyAcceptedChannel) |                    |(ProxyAcceptedChannel) |
                                                      -------------------------                    -------------------------
            Client Side                                       Proxy Side                                   Server Side

如果使用websocket,將ClientSocketAcceptor替換成ClientWebSocketAcceptor即可。

三、訊息,編解碼,加密,壓縮

ClientMessage

GameNetty裡,客戶端核和服務端之間的通訊訊息被抽象為ClientMessage,它包含三個欄位:

  • head—訊息頭

最大8位元組,使用者可選擇0,1,2,4,8,因此簡單起見,定義為long型別。
訊息頭的存在對三層結構的Proxy有重要意義,Proxy可以通過head得到必要的資訊,而避免對訊息體解碼;

  • buf—訊息體ByteBuf

此欄位用於Proxy效能優化,Proxy可以直接轉發buf,從而避免對訊息重新編碼;

  • body—訊息體物件

它是訊息體解碼後的資料物件,Proxy端可能不需要對所有訊息解析出body,在Server端,一般都需要解析body。

ProxyMessage

Proxy與Server之間的通訊訊息被抽象為ProxyMessage,它包含兩部分:ClientMessage和ProxyHead。

ClientMessage是從客戶端接收的訊息,而ProxyHead則是Proxy新增的額外資訊,就像Http代理會向Http請求插入額外頭部欄位一樣。

ProxyHead沒有強制的型別需求,簡單情況下String就足夠。

編碼

GameNetty對ClientMessage的編碼格式已經做了規定:[length(4位元組)]+[head(0~8位元組)]+[body],其中length部分是訊息完整編碼長度(包含自身)。
body部分的編解碼由使用者來實現,對應介面是MessageBodyCodec。

ProxyMessage的編碼格式也是類似的, [length(4位元組)]+[proxy head(0~8位元組)]+[ClientMessage],其中length部分是訊息完整編碼長度(包含自身)。
ProxyHead的部分的編解碼由使用者實現,對應介面是ProxyHeaderCodec。

加密,壓縮

GameNetty通過BodyTransformer機制支援對訊息的加密、壓縮,使用者可以新增一個或多個BodyTransformer,對訊息體做任意轉換。

GameNetty內建了RC4BodyEnDecryptor,GzipBody(Un)Compressor等BodyTransformer。

四、會話

GameNetty支援會話(SessionInterface介面),所謂Session,是用來標記客戶端與服務端之間的一個Channel,使用者可以在Session上附加額外的資訊;
在Client—Proxy—Server三層架構中,Session物件在Proxy上,session id具備全域性唯一性,Server通過session id來穿透Proxy與Client通訊。

五、示例

執行示例是上手GameNetty最快的方式,com.game.netty.sample下有三個示例,這些示例的功能是類似的:客戶端向服務端傳送一個訊息,服務端返回一個響應,
並且有一定概率在幾秒種後向客戶端主動推送一個訊息。

  • socket

模擬最簡單的C/S模式,執行ClientStarter(客戶端,可多個例項)和ServerStarter(服務端)即可;

  • websocket

socket的websocket版本;

  • proxy

模擬Client—Proxy—Server結構,需同時執行ClientStarter(客戶端,可多個例項),ProxyStarter(代理端),LogicServerStarter(服務端);
該示例展示了Proxy服務如何轉發Client訊息到指定的LogicServer,而後者可以通過session與指定Client通訊。

如果通過Intellij匯入程式碼,執行示例,需要配置Run Configuration->選中include dependencies with provide scope。

六、使用

建議maven匯入,參考示例使用.

<dependency>
    <groupId>com.github.longhuihu</groupId>
    <artifactId>game-netty</artifactId>
    <version>1.0</version>
</dependency>

七、聯絡人

[email protected]

個人部落格:https://blog.csdn.net/longhuihu