(十五)nodejs循序漸進-高性能游戲服務器框架pomelo之Protobuf模塊

消息壓縮?

在實際編程中,為了減少數據傳輸帶寬的消耗,提高傳輸效率,pomelo提供了對消息的壓縮,包括基于字典的對route的壓縮和基于protobuf的對具體傳輸數據的壓縮。

route壓縮

在實際編程中,網絡帶寬的有效數據負載率是一個值得考慮的問題。特別地,對于移動客戶端來說,網絡資源往往并不是很豐富,為了盡可能地節省網絡資源,往往需要盡大可能地增加數據包的有效數據率。

route問題

在pomelo編程中,pomelo中的route是用來確定消息的分發路徑,將其交給相應的服務器和服務處理的。route分為兩類,由客戶端發給服務端消息時使用的route和服務端向客戶端廣播時使用的route。

  • 前一種route是由服務器自動生成的,其中的字段就代表了對應的方法在服務端的位置。如“area.playerHandler.attack”則表示在“area”類型的服務器上的“playerHandler”提供的“attack”方法,其格式為".."。 路由信息過長,使得有效消息數據負載率大大降低。例如,在聊天應用中,如果用戶的發言僅僅是一個字符,結果不得不攜帶一個route,"chat.chatHandler.send",這樣使得有效數據負載率大大降低。

  • 后一種route是服務端想客戶端推送消息時使用,是客戶端的路由信息,如“onMove”,“onAttack”等,其格式一般為"on"這些字段是由用戶自己定義的。雖然可以定義很短的路由,但是那樣會造成可讀性變差,不利于代碼閱讀。

一般來說,當應用固定后,具體路由就不會再變動,因此可以考慮通過一種簡單替換的方式對路由信息進行壓縮。

基于dict的壓縮

pomelo中實現了基于字典的route壓縮,目前route壓縮功能僅僅支持hybridconnector,sioconnector目前無法使用route壓縮。其實現原理如下:

  • 對于系統生成的route,也就是服務端的路由信息,即格式為".."的路由信息,在系統啟動時由CoDictionary組件進行服務端路由信息掃描,然后會對每一個route生成唯一的字典項,由一個無符號小整數標識。

  • 對于用戶自定義的route,也就是客戶端的路由信息,即格式為"on",則需要用戶提供一個自定義的route列表,會根據這一個列表對每個用戶自定義的route生成一個對應的字典項,即也就是一個無符號小整數。

  • 在開啟字典功能的狀態下,使用hybridconnector的時候,當協議握手的時候,服務端會將整個字典的消息發送給客戶端,這樣客戶端和服務端都會擁有相同的具體route無符號整數的對應關系。

  • 當有消息傳遞時,其中的route在發送時會被替換為在字典項,而接收端會自動還原,這一過程對于用戶而言是完全透明的。

pomelo的protobuf實現,借助了javascript的動態性,使得應用程序可以在運行時解析proto文件,不需要進行proto文件的編譯。

pomelo的實現中,為了更方便地解析proto文件,使用了json格式,與原生的proto文件語法是相通的,但是是不相同的。?

使用protobuf

雖然protobuf的實現看上去十分復雜,但由于這一層對用戶是完全透明的,使用會非常簡單。用戶只需要通過簡單的兩步定義就可以在原有的項目中開啟protobuf功能。

  • 首先,需要在connector組件上打開protobuf開關,在app.js中的配置如下:
var Configure = function() {app.set('name', 'treasures');app.configure('production|development', 'gate', function() {app.set('connectorConfig', {connector: pomelo.connectors.hybridconnector});});app.configure('production|development', 'connector', function() {app.set('connectorConfig', {connector: pomelo.connectors.hybridconnector,heartbeat: 100,useDict: true,useProtobuf: true});});app.configure('production|development', 'area', function() {var areaId = app.get('curServer').areaId;if (!areaId || areaId < 0) {throw new Error('load area config failed');}var areaService = bearcat.getBean('areaService');var dataApiUtil = bearcat.getBean('dataApiUtil');areaService.init(dataApiUtil.area().findById(areaId));});
}
  • 實際上需要加入的就是“useProtobuf:true”這一項。當設置這一標識后,pomelo會在客戶端握手時將protos內容同步到客戶端,并默認開啟protobuf壓縮功能。

  • 在protobuf功能開啟用,用戶還需要加入protos定義來實現對具體消息的編碼/解碼。protos文件默認在/game-server/config目錄下,包括兩個文件:serverProtos.json和clientProtos.json,分別表示服務端->客戶端消息的protos和 客戶端->服務端消息的protos。只要在其中加入有效的proto定義,就可以開啟對應消息的protobuf編碼功能,CoProtobuf組件會自動加載這兩個proto文件。比如這樣定義一個serverProtos.json

    {"onPickItem" : {"required uInt32 entityId" : 1,"required uInt32 target" : 2,"required uInt32 score" : 3},"rankUpdate" : {"repeated uInt32 entities" : 1}
    }
  • 當然pomelo中的protobuf實現對原有項目是完全兼容的,你可以直接在老的項目中打開protobuf開關而不會引起任何問題。只是當proto定義是空的,默認所有的消息都不會經過protobuf壓縮,而是采用默認的二進制編碼進行傳輸。

  • 當你想對某個消息進行protobuf編碼時,只需要在對應的protos文件(serverProtos.json或clientProtos.json)中加入對應的protobuf項,pomelo在啟動時就會自動識別并對消息進行壓縮,而不會對其他未定義的消息產生任何影響。

? ? ? 那么我提供游戲里的一部分源代碼,大家可以看下如何使用proto:

? 這里在pushMessage里,route配置的是serverProto.json里的onPickItem,那么就會按照onPickItem的格式來生成編碼,里邊的字段包含了下面賦值的部分。

player.on('pickItem', function(args) {var player = self.getEntity(args.entityId);var treasure = self.getEntity(args.target);player.target = null;if (treasure) {player.addScore(treasure.score);self.removeEntity(args.target);self.getChannel().pushMessage({route: 'onPickItem',entityId: args.entityId,target: args.target,score: treasure.score});}});

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444501.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444501.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444501.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++:13---多態和虛函數表

多態的意思為“以一個public基類的指針/引用,尋址一個派生類對象”。 “多態”的關鍵在于通過基類指針或引用調用一個虛函數時,編譯時不確定到底調用的是基類還是派生類的函數,運行時才確定。這是如何實現的呢?請看下面的程序,該程序演示了多態類對象存儲空間的大小。 #in…

leetcode96. 不同的二叉搜索樹 動歸vs數學?

給定一個整數 n&#xff0c;求以 1 ... n 為節點組成的二叉搜索樹有多少種&#xff1f; 示例: 輸入: 3 輸出: 5 解釋: 給定 n 3, 一共有 5 種不同結構的二叉搜索樹: 1 3 3 2 1 \ / / / \ \ 3 2 1 1 3 …

Redis:06---數據庫管理

一、服務器中的數據庫Redis服務器將所有數據庫都保存在服務器狀態redis.h/redisServer結構的db數組中&#xff0c;db數組的每個項都是一個redis.h/redisDb結構&#xff0c;每個redisDb結構代表一個數據庫&#xff1a;struct redisServer {// ...redisDb *db; // 一個數組&#…

leetcode95. 不同的二叉搜索樹 II

給定一個整數 n&#xff0c;生成所有由 1 ... n 為節點所組成的二叉搜索樹。 示例: 輸入: 3 輸出: [ [1,null,3,2], [3,2,null,1], [3,1,null,null,2], [2,1,3], [1,null,2,null,3] ] 解釋: 以上的輸出對應以下 5 種不同結構的二叉搜索樹&#xff1a; 1 3 …

在同一局域網下連接共享文件夾失敗,提示:你不能訪問共享文件夾,因為你組織的安全策略阻止未經身份驗證的來賓訪問

1.嘗試打開guest訪問。 &#xff08;1&#xff09;使用鍵盤 win R 鍵&#xff0c;打開運行窗口&#xff0c;并輸入 gpedit.msc 打開本地組策略編輯器窗口 &#xff08;2&#xff09;選擇計算機配置------->管理模板-------->網絡-------->Lanman工作站。 &#…

(十五)深入淺出TCPIP之Hello CDN

什么是CDNCDN 其實是 Content Delivery Network 的縮寫&#xff0c;即“內容分發網絡”。CDN是將媒體資源&#xff0c;動靜態圖片(Flash) &#xff0c;HTML, CSS, JS等等內容緩存到距離你更近的互聯網數據中心&#xff0c;從而讓用戶進行共享資源&#xff0c;實現縮減站點間的響…

Redis:07---Redis數據結構

一、五大數據結構Redis可以存儲鍵與5種不同數據結構類型之間的映射&#xff0c;這5種數據結構類型分別為&#xff1a;STRING&#xff1a;字符串LIST&#xff1a;列表SET&#xff1a;集合HASH&#xff1a;散列ZSET&#xff1a;有序集合TYPE命令用來獲得鍵的數據類型&#xff0c;…

C++:14---虛繼承,虛函數,多態

一、多級混合繼承 下面先介紹菱形繼承 //菱形繼承 class A { public: int data; }; class B:public A { public: int data; }; class C:public A { public: int data; }; class D:public B,public C { public: int data; };int main() { D c; D.data=1; D.B::data=2;//訪問B中的…

(十四)nodejs循序漸進-高性能游戲服務器框架pomelo之開發Treasures游戲

#Tutorial 2 -- Treasures ##描述 Treasures 游戲是從 LordOfPomelo 中抽取出來&#xff0c;去掉了大量的游戲邏輯&#xff0c;用以更好的展示 Pomelo 框架的用法以及運作機制。 Treasures 很簡單&#xff0c;輸入一個用戶名后&#xff0c;會隨機得到一個游戲角色&#xff0c;…

leetcode243. 最短單詞距離(vip題)好像挺簡單?

給定一個單詞列表和兩個單詞 word1 和 word2&#xff0c;返回列表中這兩個單詞之間的最短距離。 示例: 假設 words ["practice", "makes", "perfect", "coding", "makes"] 輸入: word1 “coding”, word2 “practice”…

談談蘋果應用內支付(IAP)的坑

一、請求商品 下面是請求商品的代碼: - (void)validateProductIdentifier:(NSArray *)productIdentifier {SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifier]];self.request = productRe…

leetcode204. 計數質數(vip題)

統計所有小于非負整數 n 的質數的數量。 示例: 輸入: 10 輸出: 4 解釋: 小于 10 的質數一共有 4 個, 它們是 2, 3, 5, 7 。 思路&#xff1a;篩法&#xff0c;見代碼。 class Solution {public int countPrimes(int n) {// 1. 給數加上標記byte[] nums new byte[n];for (i…

如何使得客戶端和服務器端完美配合做IOS應用內付費

配置Developer.apple.com 登錄到Developer.apple.com,然后進行以下步驟: 為應用建立建立一個不帶通配符的App ID用該App ID生成和安裝相應的Provisioning Profile文件。配置iTunes Connect 登錄到iTunes Connet,然后進行以下步驟: 用該App ID創建一個新的應用。在該應用中…

IOS內購流程從0-1手把手教會

蘋果掌握著可能是全球最重要的APP分發渠道,然而30%的抽成近年來也被人批評,現在蘋果似乎也看到反對意見了,從2021年1月1日開始,部分小型企業的分成費用降低到15%。 據報道,蘋果將于2021年1月1日啟動App Store小企業項目,會降低他們的抽成費用。針對年收入不足100萬美元的…

leetcode217. 存在重復元素(vip題)超簡單

給定一個整數數組&#xff0c;判斷是否存在重復元素。 如果任何值在數組中出現至少兩次&#xff0c;函數返回 true。如果數組中每個元素都不相同&#xff0c;則返回 false。 示例 1: 輸入: [1,2,3,1] 輸出: true 示例 2: 輸入: [1,2,3,4] 輸出: false 示例 3: 輸入: [1,1,…

訂單數據持久化和驗證相關解決方案

訂單數據持久化 有時候蘋果支付在支付完成后,從蘋果服務器返回收據的過程中可能會掉單(可能是網絡問題,可能是蘋果BUG,也有一部分是開發者自身埋的坑),因此我們需要一個訂單持久化的機制來保障。 首先根據內購商品ID(此商品ID是在蘋果后臺建好的內購商品)、用戶信息(…

IOS iap處理邏輯流程圖再次梳理

序言: 本文補全一下iOS iap處理邏輯。 iap處理邏輯 蘋果退單wiki:https://developer.apple.com/documentation/storekit/in-app_purchase/handling_refund_notifications 一、上圖主要處理了以下業務: 普通購買 自動續訂訂閱 補單處理 預防黑產 退單處理 二、除了上述業…

(十七)深入淺出TCPIP之HTTP和HTTPS

超文本傳輸協議HTTP協議被用于在Web瀏覽器和網站服務器之間傳遞信息&#xff0c;HTTP協議以明文方式發送內容&#xff0c;不提供任何方式的數據加密&#xff0c;如果攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文&#xff0c;就可以直接讀懂其中的信息&#xff0c;因此&…

leetcode283. 移動零 比官方更好的解法。

給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 示例: 輸入: [0,1,0,3,12] 輸出: [1,3,12,0,0] 說明: 必須在原數組上操作&#xff0c;不能拷貝額外的數組。 盡量減少操作次數。 思路&#xff1a;記錄0的個…

C++:15---異常機制

1.概念:異常處理是一種允許兩個獨立開發的程序組件在程序執行時遇到不正常的情況相互通信的工具 2.異常檢測和異常處理的方式throw表達式:程序遇到了錯誤或者無法處理的問題,使用throw引發異常try、catch語句塊:以關鍵字tyr開始,并以一個或多個catch子句結束。它們也被稱為…