一、玩家離線
由于離線的狀況多,常見的玩家自己拿自己的賬號的離線,也有自己的賬號在多個設(shè)備來擠掉線,還有就是被非法的人使用時的擠掉線。這里應(yīng)該將玩家理解為一個賬號,下邊盡量用賬號來表述。
(一)網(wǎng)絡(luò)斷開或者主動離開游戲
這時玩家所在的服務(wù)器在玩家net.close時加入向通信redis匯報的邏輯,即通信redis里刪除這個玩家的在線紀(jì)錄。
(二)同服重復(fù)登陸時的kick
首先肯定要踢掉之前登陸的鏈接。因為同服時新舊鏈接都在這個服務(wù)器上,邏輯上簡單,允許新鏈接的登陸比較好處理,但是后邊有其他考慮。
(三)異服登陸時的kick
首先也是踢掉之前的登陸。需要在之前登陸到的服務(wù)器將該賬號的鏈接斷開并整理數(shù)據(jù)存儲之后,才能允許在新的服務(wù)器登陸。
舊服務(wù)器清理完該玩家后,向通信redis報告刪除該賬號的在線狀態(tài)。新服務(wù)器需要知道玩家已經(jīng)在舊服被kick完了才可以讓玩家登陸。剛才同服時提到的允許新鏈接立刻登陸的問題,這里就變的比較不可控了。美好的過程是,新鏈接接入后掛起在新服,等異服踢完后,繼續(xù)做新鏈接的登陸操作。但是這需要新舊服之間的同步邏輯,需要將新服玩家做個狀態(tài)機為維護這種掛起或繼續(xù)登陸狀態(tài)。另外還要考慮這個期間玩家又在另一個服登陸。要考慮的東西很多……
還有一種有問題的處理方式,即新服只是向老服發(fā)送踢人指令,新服自己卻馬上進入新鏈接的登陸操作。這樣的問題是,即使業(yè)務(wù)邏輯簡單到不會發(fā)生數(shù)據(jù)不同步問題,但登陸操作不會一定成功。新服登陸完向通信redis報告玩家在線,舊服踢完要向通信redis報告玩家離線。這兩個操作異步時,如果舊服的離線報告在后,通信redis上就會錯誤的記錄賬號當(dāng)前不在線……
(四)總結(jié)
最終重復(fù)登陸問題簡單處理方法:賬號登陸時,只要檢測到該賬號同服或異服已登陸,先將舊鏈接踢掉,再將新鏈接斷開。就給玩家一個提示“賬號已登錄,請稍后重試”,讓玩家自己來多操作幾次,直到舊鏈接被踢完。
二、同一賬號的同瞬間多起登陸事件
上邊重復(fù)登陸的檢查還有一種情況不能防止,就是瞬間的多個客戶端用同一賬號登陸。同服時由于nodejs的異步,異服時由于天然異步,檢查該賬號是否已登陸與將當(dāng)前鏈接成功登陸并向通信redis報告這些操作不具原子性。
所以在最后向通信redis寫入上線狀態(tài)時再次判斷是否已登陸(即判斷是否被瞬時并發(fā)的另一個客戶端的登陸給標(biāo)記為已上線了)。redis里用hsetnx代替hset,前者在數(shù)據(jù)已經(jīng)被設(shè)置時操作失敗。
PS:
剛接觸不久或者本身邏輯就復(fù)雜的東西(例如分布式)很多思考的結(jié)果不及時記錄的話,后邊容易忘記當(dāng)初的理由,導(dǎo)致需要冗余的重復(fù)思考。所以現(xiàn)在博客寫瑣碎些,記載些細節(jié)的思考。