這將是一個完整的,徹底踐行 DevOps/GitOps
與 Kubernetes
上雲流程的 Golang 遊戲服務器開發的系列教程。android
這個系列教程是對開源項目 Nanoserver
的完整拆解,旨在幫助你們快速上手 Golang(遊戲)服務器後端開發。經過實踐去理解 Golang 開發的精髓 —— Share memory by communication(經過通訊共享內存)
。ios
同時這個項目可能還會涉及到 Linux
性能調優(BPF
相關的工具)和系統保障(SRE
)的相關的工做。git
單體架構
理解 Mahjong Server
業務 -> Nano Distributed Game Server(分佈式)
+ 微服務
改造。若是你是用 VSCode 做爲 IDE,這個插件不錯:github
從0到1使用Golang開發生產級麻將遊戲服務器—第3篇golang
Request
:算法
POST http://192.168.31.125:12307/v1/user/login/query HTTP/1.1 content-type: application/json { "channelId": "konglai", "appId": "konglai" }
Response
:json
HTTP/1.1 200 OK Access-Control-Allow-Headers: Origin, Content-Type, Authorization Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Origin: * Content-Type: application/json; charset=utf-8 Date: Sun, 07 Feb 2021 15:00:16 GMT Content-Length: 24 Connection: close { "code": 0, "guest": true }
configs/config.toml
文件的配置,進行驗證:... [login] guest = true lists = ["test", "konglai"] ...
Request
:後端
POST http://127.0.0.1:12307/v1/user/login/guest HTTP/1.1 content-type: application/json { "channelId": "konglai", "appId": "konglai", "imei": "c0a4ce912c48a3d0b17b59e6b97f1dca" }
Response
:api
{ "code": 0, "name": "G1", "uid": 1, "headUrl": "http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0", "fangka": 10, "sex": 1, "ip": "192.168.31.125", "port": 33251, "playerIp": "192.168.31.125", "config": { "version": "1.9.3", "android": "https://fir.im/tand", "ios": "https://fir.im/tios", "heartbeat": 30, "forceUpdate": true, "title": "血戰到底", "desc": "純正四川玩法,快捷便利的掌上血戰,輕鬆組局,隨時隨地盡情遊戲", "daili1": "kefuweixin01", "daili2": "kefuweixin01", "kefu1": "kefuweixin01", "appId": "xxx", "appKey": "xxx" }, "messages": ["系統消息:健康遊戲,禁止賭博", "歡迎進入遊戲"], "clubList": [], "debug": 0 }
DB Model服務器
db/model/struct.go
type User struct { Id int64 Algo string `xorm:"not null VARCHAR(16) default"` Hash string `xorm:"not null VARCHAR(64) default"` Salt string `xorm:"not null VARCHAR(64) default"` Role int `xorm:"not null TINYINT(3) default 1"` Status int `xorm:"not null TINYINT(3) default 1"` IsOnline int `xorm:"not null TINYINT(1) default 1"` LastLoginAt int64 `xorm:"not null index BIGINT(11) default"` PrivKey string `xorm:"not null VARCHAR(512) default"` PubKey string `xorm:"not null VARCHAR(128) default"` Coin int64 `xorm:"not null BIGINT(20) default 0"` RegisterAt int64 `xorm:"not null index BIGINT(20) default 0"` FirstRechargeAt int64 `xorm:"not null index BIGINT(20) default 0"` Debug int `xorm:"not null index TINYINT(1) default 0"` }
用戶表 | 描述 |
---|---|
Id | 自增ID |
Algo | 加密算法 |
Hash | 加密hash |
Salt | 加密撒鹽 |
Role | 帳號類型(RoleTypeAdmin=1 管理員帳號,RoleTypeThird=2 三方平臺帳號) |
Status | 帳號狀態(StatusNormal=1 正常,StatusDeleted=2 刪除,StatusFreezed=3 凍結,StatusBound=4 綁定) |
IsOnline | 是否在線(UserOffline=1 離線,UserOnline=2 在線) |
LastLoginAt | 最後登陸時間 |
PrivKey | 帳號證書私鑰 |
PubKey | 帳號證書公鑰 |
Coin | 房卡數量 |
RegisterAt | 註冊時間 |
FirstRechargeAt | 首充時間 |
Debug | 用戶信息調試 |
type Register struct { Id int64 Uid int64 `xorm:"not null index BIGINT(20) default"` Remote string `xorm:"not null VARCHAR(40) default"` Ip string `xorm:"not null VARCHAR(40) default"` Imei string `xorm:"not null VARCHAR(128) default"` Os string `xorm:"not null VARCHAR(20) default"` Model string `xorm:"not null VARCHAR(20) default"` AppId string `xorm:"not null index VARCHAR(32) default"` ChannelId string `xorm:"not null index VARCHAR(32) default"` RegisterAt int64 `xorm:"not null index BIGINT(11) default"` RegisterType int `xorm:"not null index TINYINT(8) default"` }
用戶註冊記錄表 | 描述 |
---|---|
Id | 自增ID |
Uid | 用戶ID |
Remote | 外網IP |
Ip | 內網IP |
Model | 硬件型號 |
Imei | 設備的imei號 |
Os | os版本號 |
AppId | 應用id |
ChannelId | 渠道id |
RegisterAt | 註冊時間 |
RegisterType | 註冊類型(RegTypeThird=5 三方平臺添加帳號) |
type Login struct { Id int64 Uid int64 `xorm:"not null index BIGINT(20) default"` Remote string `xorm:"not null VARCHAR(40) default"` Ip string `xorm:"not null VARCHAR(40) default"` Model string `xorm:"not null VARCHAR(64) default"` Imei string `xorm:"not null VARCHAR(32) default"` Os string `xorm:"not null VARCHAR(64) default"` AppId string `xorm:"not null VARCHAR(64) default"` ChannelId string `xorm:"not null VARCHAR(32) default"` LoginAt int64 `xorm:"not null BIGINT(11) default"` LogoutAt int64 `xorm:"not null BIGINT(11) default"` }
用戶登陸記錄表 | 描述 |
---|---|
Id | 自增ID |
Uid | 用戶ID |
Remote | 外網IP |
Ip | 內網IP |
Model | 硬件型號 |
Imei | 設備的imei號 |
Os | os版本號 |
AppId | 應用id |
ChannelId | 渠道id |
LoginAt | 登陸時間 |
LogoutAt | 註銷時間 |
AppID
(用戶來自於哪個應用
) 與 Device.IMEI
(設備的imei號
),肯定當前遊客是否已經註冊user, err := db.QueryGuestUser(data.AppID, data.Device.IMEI)
db.QueryGuestUser
,會從 register
或 user
表中去查找用戶是否存在。
相關 protocol
的定義:
protocol/login.go
type LoginRequest struct { AppID string `json:"appId"` //用戶來自於哪個應用 ChannelID string `json:"channelId"` //用戶來自於哪個渠道 IMEI string `json:"imei"` Device Device `json:"device"` }
protocol/common.go
type Device struct { IMEI string `json:"imei"` //設備的imei號 OS string `json:"os"` //os版本號 Model string `json:"model"` //硬件型號 IP string `json:"ip"` //內網IP Remote string `json:"remote"` //外網IP }
涉及到的相關 db
常量的定義:
db/const.go
const ( StatusNormal = 1 //正常 StatusDeleted = 2 //刪除 StatusFreezed = 3 //凍結 StatusBound = 4 //綁定 ) const ( UserOffline = 1 //離線 UserOnline = 2 //在線 ) // Users表中role字段的取值 const ( RoleTypeAdmin = 1 //管理員帳號 RoleTypeThird = 2 //三方平臺帳號 )
生成一個新用戶:
const defaultCoin = 10 // 默認給的房卡數量是 10 user = &model.User{ Status: db.StatusNormal, IsOnline: db.UserOffline, Role: db.RoleTypeThird, Coin: defaultCoin, } db.InsertUser(user)
註冊一條用戶記錄
db.RegisterUserLog(user, data.Device, data.AppID, data.ChannelID, protocol.RegTypeThird) //註冊記錄
login
響應數據相關 protocol
的定義:
protocol/login.go
type LoginResponse struct { Code int `json:"code"` Name string `json:"name"` Uid int64 `json:"uid"` HeadUrl string `json:"headUrl"` FangKa int64 `json:"fangka"` Sex int `json:"sex"` //[0]未知 [1]男 [2]女 IP string `json:"ip"` Port int `json:"port"` PlayerIP string `json:"playerIp"` Config ClientConfig `json:"config"` Messages []string `json:"messages"` ClubList []ClubItem `json:"clubList"` Debug int `json:"debug"` } type ClientConfig struct { Version string `json:"version"` Android string `json:"android"` IOS string `json:"ios"` Heartbeat int `json:"heartbeat"` ForceUpdate bool `json:"forceUpdate"` Title string `json:"title"` // 分享標題 Desc string `json:"desc"` // 分享描述 Daili1 string `json:"daili1"` Daili2 string `json:"daili2"` Kefu1 string `json:"kefu1"` AppId string `json:"appId"` AppKey string `json:"appKey"` }
protocol/club.go
type ( ClubItem struct { Id int64 `json:"id"` Name string `json:"name"` Desc string `json:"desc"` Member int `json:"member"` MaxMember int `json:"maxMember"` } // .... )
device := protocol.Device{ IP: ip(r.RemoteAddr), Remote: r.RemoteAddr, } db.InsertLoginLog(user.Id, device, data.AppID, data.ChannelID) return resp, nil
關於遊戲服務器登陸與 Nano 遊戲服務器通訊相關代碼實戰,咱們下篇再詳細討論。
我是爲少 微信:uuhells123 公衆號:黑客下午茶 加我微信(互相學習交流),關注公衆號(獲取更多學習資料~)