挺久沒更新文章了,這一年以來個人經歷了許多事情,去年下半年開始穩定下來了,但今年初始又趕上疫情,公司的項目進度也推遲了,現在好不容易復工,登錄了許久不上的博客,發現自己收到了很多新的關注和私信,也有很多網友表達了對自己文章的支持,在這裏先表達自己的感謝。其次對於一些網友詢問的問題,在這裏統一回復下:之前那一系列對於英雄遠征源碼分析的文章質量其實不高,各位隨便看看就行了...至於交流,本人工作經驗尚淺,不是什麼大神,就不打擾浪費大家時間了...至於上一篇英雄遠征的Erlang源碼,有時間會重新整理一遍,附加一些運行說明,確保都能跑起來。
閒話不多說了,最近在參與公司的新項目,對涉及到好友系統的部分有一些自己的理解和疑惑,在此隨手記錄一下
確認幾個前提:
遊戲中每個玩家是一個語言級別的輕量級的進程,A進程要給B進程發送消息需要使用語言層面的RPC調用。
玩家的好友數據保存在數據庫和內存緩存中。
離線事件:有專門的離線事件管理進程,當給離線玩家派發一個事件(比如有人給其發送了好友申請),進程會將事件先進行保存(數據庫,緩存),玩家上線時通過離線事件管理進程取出,並執行其中的操作(收到該好友申請)。
保存的好友結構:
好友列表
臨時好友列表
申請列表
黑名單列表
先抽出一個最簡單的過程:
添加好友:A向B申請好友,B收到A的申請,彈出“XXX請求添加你爲好友 確認 拒絕”,B點了確認,則A出現在了B的好友列表中,B自己也被添加到了A的好友列表
刪除好友:A把B從好友列表刪除,則A自己也從B的好友列表消失了
黑名單:不再贅述
這些操作在對方離線的時候也是可執行的。
加好友過程:
A申請B:A向B發送申請請求,B收到請求後將A放入申請列表
B同意A:B向A發送同意信息,將A從申請列表中刪除,放入臨時好友列表
B拒絕A:B向A發送拒絕信息,將A從申請列表中刪除
A收到B的同意:A自動向B發送確認同意信息,將B放入好友正式列表
B收到A的確認:B將A放入好友正式列表
有點像TCP三次握手
(1)A -> B:請求好友(請求建立連接)
(2)A <- B:同意好友(同意建立連接)
(3)A -> B:確認好友(確認建立連接)
中間任一個階段條件檢查未通過都不能成功加好友
條件檢查涉及幾個地方:目標玩家是否存在,自己的好友列表是否已滿,對方的好友列表是否已滿,是否已經建立關係,是否被拉黑
需要進行條件檢查的地方:A給B發申請前;B收到申請時;B給A回覆同意時;A給B發送確認時;B收到A的確認時。
其中每個階段,任一方都有可能離線,需要進行離線事件的處理
在線的情況:
A向B發出申請時,B將A放入申請列表。
B選擇同意好友,將A從申請列表中刪除,同時加入自己的臨時好友列表(因爲A那邊沒確認),給A發出同意信息
A給B發出確認添加好友的信息,B收到A的確認信息後不用再回復,只要把A從臨時列表刪除,加入到好友列表中即可。
離線的情況:
一個原則:任一玩家無法修改其他離線玩家的數據。
A向B發出申請,B離線,給B發離線事件,A下線。
B上線,取出離線事件,把A加入申請列表;同意A的申請,把A從申請列表刪除,加入自己的臨時列表。此時A離線,但又不能讓B等待A返回的確認結果(玩遊戲的時候確實沒等),於是決定讓離線進程代替A進行確認的判斷,把加好友的數據寫入離線進程,給B返回確認的結果。等A上線後從離線進程取出離線期間加好友的數據,再寫回給A。
離線進程/A在線,返回了確認的結果但B離線(剛同意完以很快的速度下線了,或者網比較卡),給B發同意的離線事件。
B上線,取出離線事件,把A從臨時列表刪除,加入正式的好友列表。
也有直接使用公共緩存保存好友數據的方式,每次好友關係的變動無論對方是否在線都只需要修改公共緩存,緩存定期同步到數據庫中。離線轉換爲在線狀態時,只需要從公共緩存中加載自己的好友數據。
刪除好友步驟(雙向):
A想刪掉B,此時先把B從好友列表刪除。
如果B在線,則把B列表中的A刪除;如果B離線,則給B派發離線事件,等B上線把A從B的好友列表中刪除
黑名單步驟(單向):
A拉黑B,直接把B加入黑名單列表中。
推薦好友列表:
隨便隨機幾個
極端情況考慮:
現在我們有三個人:A,B和C,
情況1:A和B同時向C發出申請,但C只有一個好友位置
此時C首先同意了A的申請,將A加入自己的好友列表,同時C的好友列表已滿,則C無法再同意B的申請。需要在C同意B時對C的好友列表進行檢查。是需要在同意階段(2)檢查被申請方的好友列表長度。
情況2:A向B發出申請,B向C發出申請,但B只有一個好友位置
若B先同意了A發出的申請,則C無法再同意B的申請。是需要在確認階段(3)對申請方好友列表長度進行檢查。
若C先同意了B的申請,則B無法同意A的申請。是需要在同意階段(2)檢查被申請方的好友列表長度。
情況3:A申請B,B申請C,C申請A,此時每個人都是隻有一個好友列表
其實也沒那麼複雜:若B同意了A,則C無法同意B,A無法同意C。需要在好友確認階段(3)檢查申請方好友列表長度,在同意階段(2)檢查被申請方好友列表長度。
情況4:A向B申請了,B也向A申請了
此時A和B都在相互的申請列表中,申請過程中只要做好是否已經是好友的檢查問題應該不大。
要防止超出好友列表長度,只需要在同意階段(2)檢查被申請方好友列表長度,確認階段(3)檢查申請方好友列表長度即可。不過考慮實際需求變化和保險起見,最好能想到的地方都加上相關檢查。
幾個疑問:
參考了一些網絡上的文章,好友系統的設計只有兩個步驟:請求好友(1)和同意好友(2),那麼本文中的第三個步驟確認好友(3)是否是多餘的,正如TCP的三次握手,如果涉及到“確認”這一步,可能會掉入A給B發送消息,B給A發送確認消息,A給B發送確認消息的確認...一種循環中,而如果將TCP三次握手中的第三次去掉的話,影響會和好友系統中去掉確認好友(3)步驟一樣嗎。說到底,拿添加好友的過程類比TCP三次握手是否恰當...
...