online游戲服務器架構—用戶登錄數據組織 .

sprite_t類型的數據結構是核心數據結構,每一個登錄用戶對應一個,它的初始化在用戶登錄的時候,此后一直到用戶退出或者離線一直保存在系統內存當中,在此過程中該sprite_t數據結構被保存在兩個哈希表當中,一個是以用戶的id為索引,這個是邏輯相關的,另一個是以此連接的套結字描述符為索引,這個是邏輯無關的:

int parse_protocol(uint8_t *data, int rcvlen, fdsession_t* fdsess)

{

protocol_t pkg;

sprite_t *p, tmp; //tmp是個局部變量,分配于棧上,由于此后的執行續是串行的,也就是說在動態分配sprite_t數據結構于堆上之前并不清除此函數的調用棧幀,因此這里使用局部變量很安全。

int i;

i = 0;

//此處用UNPKG_XX系列解析pkg.len, pkg.ver, pkg.cmd, pkg.id, pkg.ret

p = get_sprite_by_fd(fdsess->fd); //以套結字描述符查找sprite_t數據結構,如果該用戶已經登錄,那么一定能查找到的,因為用戶和online的交互是長連接,如果是登錄包,那么肯定查不到,因為這是第一個包

if ((pkg.cmd != PROTO_LOGIN && !p) || (pkg.cmd == PROTO_LOGIN && p) …){

ERROR_RETURN(("pkg error”);

}

if (pkg.cmd == PROTO_LOGIN) {

sprite_t* old = get_sprite(pkg.id); //以id為索引查找該用戶是否已經登錄

if (old) notify_user_exit(old, -ERR_multi_login, 1); //如果已經登錄,那么踢出已經登錄的用戶

p = &tmp;

memset(p, 0, sizeof(*p));

p->id = pkg.id; //設置用戶的id,登錄期間一定唯一

p->item_cnt = 0;

p->fd = fdsess->fd; //設置fd,套結字描述符,一定是唯一的

p->fdsess = fdsess;

}

return dispatch_protocol(p, pkg.cmd, data + sizeof (pkg), pkg.len - sizeof (pkg));

}

由此可見,一個sprite_t數據結構連接在兩個哈希列表中,一個是套結字描述符為索引的,另一個是用戶id為索引的,注意這兩個索引都是唯一的索引。每每分配一個sprite_t數據結構都要將之插入到兩個哈希表當中,以套結字描述符為索引的查找函數如下:

sprite_t* get_sprite_by_fd(int fd)

{

sprite_t* p = g_hash_table_lookup(all_sprites, &fd);

if ( !p || IS_NPC_ID(p->id) )

return 0;

return p;

}

以用戶id為索引的查找函數如下:

static inline sprite_t *get_sprite (uint32_t id)

{

sprite_t *p;

list_for_each_entry (p, &idslots[id % HASH_SLOT_NUM], hash_list)

if (p->id == id)

return p;

return NULL;

}

對于登錄包,最終dispatch_protocol會進入到auth_cmd,該函數對用戶的一些信息進行一些如MD5之類的驗證,然后進入到do_auth函數:

static inline int

do_auth(sprite_t* v)

{

sprite_t* p = add_sprite(v); //該函數將新分配的sprite_t數據結構插入到兩個哈希鏈表當中

notify_user_login(p, 1);

ADD_TIMER_EVENT(p, long_time_min45_in_game, 0, now.tv_sec + 45*60);

ADD_TIMER_EVENT(p, long_time_min10_in_game, 0, now.tv_sec + 10*60);

if (IS_GUEST_ID(p->id)) { //如果是訪客的話進入下面流程

enter_map(p, 1, 0); //為訪客直接設置地圖

rsp_proto_login(p);

return 0;

} else {

return db_get_sprite_with_mail(p);

}

}

sprite_t* add_sprite(sprite_t* v)

{

sprite_t* p = alloc_sprite(v->fd);

*p = *v;

p->stamp = now.tv_sec;

INIT_LIST_HEAD(&p->hash_list);

INIT_LIST_HEAD(&p->map_list);

INIT_LIST_HEAD(&p->timer_list);

list_add_tail(&p->hash_list, &idslots[p->id % HASH_SLOT_NUM]); //插入到以用戶id為索引值的哈希鏈表

return p;

}

static inline sprite_t* alloc_sprite(int fd)

{

sprite_t* p = g_slice_alloc(SPRITE_STRUCT_LEN); //分配一個sprite_t數據結構

p->fd = fd; //初始化一個套結字索引值

g_hash_table_insert(all_sprites, &(p->fd), p); //以套結字描述符為索引插入到全局的哈希鏈表

++sprites_count;

return p;

}

enter_map是一個很重要的函數,它設置了玩家的地圖信息,每一個地圖都是一個數據結構map_t,里面包含一個list_head類型的數據結構sprite_list_head,而每一個sprite_t數據結構都有一個list_head類型的map_list,每次初始化完了一個sprite_t之后最終都要調用一個list_add_tail (&p->map_list, &tile->sprite_list_head)將該sprite_t加入到一個map的list當中,這里的list_head就是linux內核中的最常見的list_head數據結構

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

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

相關文章

leetcode300 最長上升子序列

經典題&#xff0c;不解釋&#xff0c;可以看我之前文章。 普通dp public class Solution {public int lengthOfLIS(int[] nums) {if (nums.length 0) {return 0;}int[] dp new int[nums.length];dp[0] 1;int maxans 1;for (int i 1; i < dp.length; i) {int maxval …

Github(5)-開源開發-常見錯誤

使用github 托管代碼簡單使用教程--開源開發-常見錯誤5. github開源開發6. 報錯log6.1 fatal: remote origin already exists.6.2 There is no tracking information for the current branch.6.標簽管理廖雪峰老師博文學習筆記&#xff1a;https://www.liaoxuefeng.com/wiki/89…

online游戲服務器架構--數據庫及事件相關 .

Online服務器的第三部分就是數據層&#xff0c;send_request_to_db開始了數據層的處理邏輯&#xff1a; int send_request_to_db(int cmd, sprite_t* p, int body_len, const void* body_buf, uint32_t id)&#xff1b; 在該函數里首先以懶惰的方式連接數據庫服務器&#xff…

leecode5 最長回文子串

給定一個字符串 s&#xff0c;找到 s 中最長的回文子串。你可以假設 s 的最大長度為 1000。 示例 1&#xff1a; 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2&#xff1a; 輸入: "cbbd" 輸出: "bb"…

libxml解析xml文件的一些總結

libxml -- 解析 XML 文檔XML 介紹&#xff1a;XML 和 DOMlibxml 介紹 數據類型 — xmlChar數據結構 創建 XML 文檔解析 XML 文檔修改 xml 文檔Xpath — 處理大型 XML 文檔libxml2 庫函數要注意的函數讀取 xml 文件xml 操作基本結構及其指針類型根節點相關函數 創建子節點相關函…

Linux(7)-正則表達式

正則表達式demo1:在某個文件中尋找命令seddemo2:尋找8位電話號碼正則表達式&#xff1a;用來描述或者匹配某一系列符合某個句法隊則的字符串或者單個字符串。最初正則表達式&#xff0c;出現在自動控制理論和形式化語言理論中。 Linux 中 find grep sed ls命令都支持正則表達式…

服務器端開發的一些建議

摘要: 本文作為游戲服務器端開發的基本大綱&#xff0c;是游戲實踐開發中的總結。第一部分專業基礎&#xff0c;用于指導招聘和實習考核&#xff0c; 第二部分游戲入門&#xff0c;講述游戲服務器端開發的基本要點&#xff0c;第三部分服務端架構&#xff0c;介紹架構設計中的一…

leetcode63 不同路徑II

一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為“Start” &#xff09;。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為“Finish”&#xff09;。 現在考慮網格中有障礙物。那么從左上角到右下角將…

小談Online-game服務器端設計(1、2)

談這個話題之前&#xff0c;首先要讓大家知道&#xff0c;什么是服務器。在網絡游戲中&#xff0c;服務器所扮演的角色是同步&#xff0c;廣播和服務器主動的一些行為&#xff0c;比如說天氣&#xff0c;NPC AI之類的&#xff0c;之所以現在的很多網絡游戲服務器都需要負擔一些…

Linux(8)-Linux下的編程開發-C/C++、PHP、JAVA概述

Linux下的編程開發1.C/C語言開發環境的搭建2.PHP開發環境搭建3.JAVA開發環境搭建1.C/C語言開發環境的搭建 方式1:文本編輯器編譯器&#xff08;gcc/g&#xff09; Ubuntu 下常用的文本編輯器&#xff1a; Gedit–語法高亮Vim–vi(無比強大無比難用)的改進。字符界面/圖形界面…

leetcode55 跳躍游戲 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 判斷你是否能夠到達最后一個位置。 示例 1: 輸入: [2,3,1,1,4] 輸出: true 解釋: 我們可以先跳 1 步&#xff0c;從位置 0 到達 位置 1, 然后再從位置 …

小談Online-game服務器端設計(3)

下面我想來談談關于服務器上NPC的設計以及NPC智能等一些方面涉及到的問題。首先&#xff0c;我們需要知道什么是NPC&#xff0c;NPC需要做什么。NPC的全稱是&#xff08;Non-Player Character&#xff09;&#xff0c;很顯然&#xff0c;他是一個character&#xff0c;但不是玩…

小談Online-game服務器端設計(4)

在這一章節&#xff0c;我想談談關于服務器端的腳本的相關設計。因為在上一章節里面&#xff0c;談NPC智能相關的時候已經接觸到一些腳本相關的東東了。還是先來談談腳本的作用吧。   在基于編譯的服務器端程序中&#xff0c;是無法在程序的運行過程中構建一些東西的&#xf…

leetcode45 跳躍游戲II 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 你的目標是使用最少的跳躍次數到達數組的最后一個位置。 示例: 輸入: [2,3,1,1,4] 輸出: 2 解釋: 跳到最后一個位置的最小跳躍數是 2。 從下標為 …

MachineLearning(7)-決策樹基礎+sklearn.DecisionTreeClassifier簡單實踐

sklearn.DecisionTreeClassifier決策樹簡單使用1.決策樹算法基礎2.sklearn.DecisionTreeClassifier簡單實踐2.1 決策樹類2.3 決策樹構建2.3.1全數據集擬合&#xff0c;決策樹可視化2.3.2交叉驗證實驗2.3.3超參數搜索2.3.4模型保存與導入2.3.5固定隨機數種子參考資料1.決策樹算法…

游戲服務器體系結構

本文描述了一個我所設計的游戲服務器體系結構,其目的是實現游戲服務器的動態負載平衡,將對象從繁忙的服務器轉移到相對空閑的服務器中.設計并沒有經過具體的測試與驗證,僅僅是將自己目前的一些想法記錄下來.隨著新構思的出現,可能會有所變化. 以下是服務器的邏輯視圖,其中忽略…

游戲服務器架構探討

要描述一項技術或是一個行業&#xff0c;一般都會從其最古老的歷史開始說起&#xff0c;我本也想按著這個套路走&#xff0c;無奈本人乃一八零后小輩&#xff0c;沒有經歷過那些苦澀的卻令人羨慕的單機游戲開發&#xff0c;也沒有響當當的拿的出手的優秀作品&#xff0c;所以也…

leetcode72 編輯距離

給定兩個單詞 word1 和 word2&#xff0c;計算出將 word1 轉換成 word2 所使用的最少操作數 。 你可以對一個單詞進行如下三種操作&#xff1a; 插入一個字符 刪除一個字符 替換一個字符 示例 1: 輸入: word1 "horse", word2 "ros" 輸出: 3 解釋: ho…

即時通訊系統架構

有過幾款IM系統開發經歷&#xff0c;目前有一款還在線上跑著。準備簡單地介紹一下大型商業應用的IM系統的架構。設計這種架構比較重要的一點是低耦合&#xff0c;把整個系統設計成多個相互分離的子系統。我把整個系統分成下面幾個部分&#xff1a;&#xff08;1&#xff09;狀態…

leetcode303 區域和檢索

給定一個整數數組 nums&#xff0c;求出數組從索引 i 到 j (i ≤ j) 范圍內元素的總和&#xff0c;包含 i, j 兩點。 示例&#xff1a; 給定 nums [-2, 0, 3, -5, 2, -1]&#xff0c;求和函數為 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0,…