遊戲伺服器(Nano)登入 & 遊戲資料包通訊實戰
系列文章
介紹
這將是一個完整的,完全踐行 DevOps/GitOps
與 Kubernetes
上雲流程的 Golang 遊戲伺服器開發的系列教程。
這個系列教程是對開源專案 Nanoserver
的完整拆解,旨在幫助大家快速上手 Golang(遊戲)伺服器後端開發。通過實踐去理解 Golang 開發的精髓 —— Share memory by communication(通過通訊共享記憶體)
。
同時這個專案可能還會涉及到 Linux
效能調優(BPF
相關的工具)和系統保障(SRE
)的相關的工作。
Step-By-Step 開發 Mahjong Server
單體架構
理解Mahjong Server
業務 ->Nano Distributed Game Server(分散式)
+微服務
改造。- Demo:go-mahjong-server
客戶端連線遊戲伺服器
遊戲伺服器開啟 Debug Mode
服務端加入 nano.WithDebugMode()
後,會有詳細的日誌輸出。
// internal/game/game.go
nano.Listen(addr,
nano.WithPipeline(pip),
nano.WithHeartbeatInterval(time.Duration(heartbeat)*time.Second),
nano.WithLogger(log.WithField("component", "nano")),
nano.WithSerializer(json.NewSerializer()),
nano.WithComponents(comps),
nano.WithDebugMode(),
)
檢視登入日誌
...
...
time="2021-02-18T23:01:16+08:00" level=info msg="New session established: Remote=192.168.31.125:62569, LastTime=1613660476" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="Session handshake Id=2, Remote=192.168.31.125:62569" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="Receive handshake ACK Id=2, Remote=192.168.31.125:62569" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="UID=0, Message={Request Manager.Login (195bytes)}, Data=&{Name:G1 Uid:1 HeadUrl:http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0 Sex:1 FangKa:10 IP:192.168.31.125}" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="玩家: 1登入: &{Name:G1 Uid:1 HeadUrl:http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0 Sex:1 FangKa:10 IP:192.168.31.125}"
time="2021-02-18T23:01:16+08:00" level=info msg="玩家: 1不線上,建立新的玩家"
time="2021-02-18T23:01:16+08:00" level=info msg="Add session to group _SYSTEM_MESSAGE_BROADCAST, ID=2, UID=1" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="Type=Response, ID=2, UID=1, MID=1, Data=&{Uid:1 Nickname:G1 HeadUrl:http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0 Sex:1 FangKa:10}" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="[SQL] SELECT `id`, `algo`, `hash`, `salt`, `role`, `status`, `is_online`, `last_login_at`, `priv_key`, `pub_key`, `coin`, `register_at`, `first_recharge_at`, `debug` FROM `user` WHERE `id`=? LIMIT 1 []interface {}{1}" component=model orm=xorm
time="2021-02-18T23:01:16+08:00" level=info msg="Type=Push, ID=2, UID=1, Route=onCoinChange, Data=&{Coin:10}" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="Receive handshake ACK Id=2, Remote=192.168.31.125:62569" component=nano
time="2021-02-18T23:01:16+08:00" level=info msg="UID=1, Message={Request DeskManager.UnCompleteDesk (2bytes)}, Data=[91 93]" component=nano
time="2021-02-18T23:01:16+08:00" level=debug msg="DeskManager.UnCompleteDesk: 玩家不在房間內" player=1
time="2021-02-18T23:01:16+08:00" level=info msg="Type=Response, ID=2, UID=1, MID=2, Data=&{Exist:false TableInfo:{DeskNo: CreatedAt:0 Creator:0 Title: Desc: Status:建立 Round:0 Mode:0}}" component=nano
...
...
分析日誌
很清晰的看到三條 info
級別的 log
:
New session established
(有一個連線進來了,建立新的會話)Session handshake
(客戶端向伺服器發起握手請求)Receive handshake ACK
(握手成功,客戶端向伺服器傳送一個握手ACK
)
其實這個就是遊戲客戶端與遊戲伺服器(Nano
框架)的握手?過程。
當底層連線建立後,客戶端向伺服器發起握手請求,並附帶必要的資料。伺服器檢驗握手資料後,返回握手響應。如果 握手成功,客戶端向伺服器傳送一個握手ack,握手階段至此成功結束。更多,請檢視官方Nano 通訊協議
接下來我們看到如下日誌:
UID=0, Message={Request Manager.Login (195bytes)}, Data=&{Name:G1 Uid:1 HeadUrl:http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0 Sex:1 FangKa:10 IP:192.168.31.125}
表示遊戲客戶端(Game Client
)向遊戲伺服器(Game Server
)的路由 Manager.Login
傳送了一個訊息型別為 Request
的資料包。
Manager.Login
關於 Nano
基礎知識,這裡不在贅述:
5 分鐘上手 Nano 遊戲伺服器框架
業務程式碼邏輯分析
- 為當前
Session
繫結玩家uid
- 查詢玩家列表
- 玩家不線上,建立新的玩家
- 玩家的遊戲資料初始化
- 繫結
Session
到當前玩家 - 非同步從資料庫同步房卡
- 將玩家加入到玩家列表統一管理
- 玩家線上
- 重置之前的session
- 繫結新session
- 新增到廣播頻道
- 響應結果
涉及到的通訊協議:
protocol/login.go
type LoginToGameServerRequest struct {
Name string `json:"name"`
Uid int64 `json:"uid"`
HeadUrl string `json:"headUrl"`
Sex int `json:"sex"` //[0]未知 [1]男 [2]女
FangKa int `json:"fangka"`
IP string `json:"ip"`
}
type LoginToGameServerResponse struct {
Uid int64 `json:"acId"`
Nickname string `json:"nickname"`
HeadUrl string `json:"headURL"`
Sex int `json:"sex"`
FangKa int `json:"fangka"`
}
一圖勝千言
我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)