雲原生專案實踐DevOps(GitOps)+K8S+BPF+SRE,從0到1使用Golang開發生產級麻將遊戲伺服器—第5篇

為少發表於2021-02-21

遊戲伺服器(Nano)登入 & 遊戲資料包通訊實戰

系列文章

  1. Golang開發生產級麻將遊戲伺服器—第1篇
  2. Golang開發生產級麻將遊戲伺服器—第2篇
  3. Golang開發生產級麻將遊戲伺服器—第3篇
  4. Golang開發生產級麻將遊戲伺服器—第4篇

介紹

這將是一個完整的,完全踐行 DevOps/GitOpsKubernetes 上雲流程的 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
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)

相關文章