如有错误的地方,请同仁指正,非常感谢
第一种方式:
共3个进程
Login: 登陆服(同时用于聊天系统) socket长连接
Game: 游戏服(游戏逻辑处理) http短连接
Mysql: 数据库回写 socket
客户端socket连接login,保持长连接,验证成功后,向game服以http方式请求数据
game服向login服http方式验证该客户端是否已经正常登陆, 1: 没有登录则,game返回数据给客户,没有登录状态. 2: 已经登陆,则game返回所需数据给客户端.
game将修改后的数据以sql语句形式发送给mysql服,同时记录当前sql到文件中用于备查.
使用单独login服的好处在于 客户端可以一直保持连接,并且login服逻辑处理少. 服务器压力小.同时在game服有问题需要闪断时,还能继续保持玩家登陆状态,在紧急更新game服后,客户端不需要重新连接登陆游戏. 并且因为login较少的逻辑处理, 各个socket共存连接能力相应变强.可以提高同时在线玩家数. 使用socket连接,便于服务端主动向客户端发送聊天,公告等信息. 与game服连接方式不同,主要是因为两个进程间功能不同导致.
game服使用http方式,http处理能力相较于socket更好,使用更方便,基本不需要去考虑网络连接的状态问题.客户端需要什么数据,可以直接Get请求. 对于每次请求数据,都是单独一个go程, http并发处理也会更好.
具体实现:
login服只读取玩家的Account信息用于验证.不生成新sql数据. 如果新用户登陆,则生成一份临时数据用于表示新用户登陆成功.返回给客户端一个uid.作为客户端登陆的标记. 客户端向game服请求数据时,再由game生成sql数据,同时get方式通知login服临时数据为永久数据. sql语句通知mysql服回写数据.
客户端每次向game请求数据都需要带上参数uid, game服使用uid向login服通过http方式验证客户端是否已经登陆成功. 1:没有登录则提醒登陆 2.已经登陆,则处理逻辑数据 (这里有个问题,game与login直接的验证会非常频繁)
game服的数据处理,则使用内存共享方式.
game服启动时将mysql数据库中的数据全部读取到内存中. 结构如下:
type UserData struct{//单个玩家的结构数据
Account Account //单个玩家的账号信息,元宝,铜钱等属性
Bag []Bag //单个玩家的背包物品数据. 多个物品
Friend []Friend //单个玩家的好友 多个好友
....
mu sync.RWMutex //单个玩家的数据锁
}
UserDatas = make(map[int32]UserData) //全服所有玩家数据
type Shop struct{ //商店表 配置表
....
}
ShopInfo = make(map[int32] Shop) //商店的配置表数据
......
说明a: 玩家的信息,统一放在UserData中,多条数据使用slice结构,尽量减少"对象"数量.
不能统一的数据则单独一个结构.
game服在游戏过程中,只要数据变化则生成优化后的sql语句,通知mysql服回写到数据库
mysql服只负责接收sql语句, 并写入到数据库,记录下当前写成功的sql语句第几条.用于数据出错时. 对比sql文件,已经写到哪一条语句.便于恢复数据库. 如果一旦数据回写错误,则停止接下去的语句回写, 需要记录下后续语句的数量即可, 并马上通知dba管理员.
说明b: 如果一个玩家操作需要影响到其它玩家,则由game服请求login服,由login服主动通知客户端数据.免去了客户端定时请求某些操作的麻烦.
例如: A玩家在地图上移动,需要通知周边其它玩家,A玩家新的坐标点. 此时由game服请求login服,login服通知在线玩家A的新数据.
第二种方式:
纯http连接.
game服: http连接
mysql服:数据回写处理.
A玩家向game请求登陆,game验证成功后,记录A玩家登陆成功,并返回给客户端uid.则此后3分钟都认为该uid的玩家处于登陆状态. A客户端每次请求数据都更新A玩家的最后时间.
其中uid为加密后的数据. 每次重新验证则生成不同的uid.
纯http的弊端: 服务器不能实时通知客户端信息.
游戏中建立玩家数据更新标志位. 如A玩家定时2-5秒请求公告标志位,发现公告标志位是新的,则读取.
A玩家移动,需要通知其它周边玩家, 则向其它玩家的移动处理队列中添加新数据,并更新通知标志位, B玩家每1-2秒请求检查标志位状态,有新数据则获取.
以上两种方式,其中数据传输该加密的方式则需要加密.
本人新手,求达人指正
有疑问加站长微信联系(非本文作者)