Git地址:https://github.com/0990/goserver
作者一直想搭建一个自己的游戏服务器架构,近来有时间就开始着手,要求有以下两点:
1,支持protobuf,websocket,因为本人从事过cocos creator客户端,基本目标就是和cocos creator的客户端能正常通信
2,服务器架构支持分布式,这样可以支持横向扩展
一般分布式游戏服务有网关服务器、游戏服务器、中心服务器基本要素,这里也不例外,网关服务器负责建议和维护客户端的通信,转发消息到其它服务器;游戏服务器负责游戏逻辑,压力大时可多开,中心服务器负责维护所有游戏状态和玩家状态
1,网关服:
网关服务器和客户端通信使用gorilla websocket,这样可以直接对接cocos creator,
通信格式如下:
-------------------------
| id | protobuf message |
-------------------------
id是protobuf消息名字的hash值,用于反解析数据,目前未加入加密
网关服主要作用是转发消息到其它服,常用接口
g.RouteSessionMsg((*pb.ReqHello)(nil), BServerID)
对于收到此消息的服务器请求,需要注册处理事件:
s.RegisterSessionMsgHandler(func(client rpc.Session, req *pb.ReqHello) {
resp := &pb.RespHello{Name:"回复您的请求"}
client.SendMsg(resp)
})
2,服务器之间通信
一般来说服务间通信有notify(只发送消息),request请求,call请求,request和call区别在于,call请求后会阻塞当前线程,等到返回消息到来或超时,才会继续,而request不会
服务器之间的rpc有多种方式可以实现,我选择消息队列nats作为一个尝试,nats是高性能的消息队列服务,常用接口是publish(发布)和subscribe(订阅),在goserver中,每个服务器都订阅自己的服务器消息,A向B发消息就publish(B,msgData),B回A消息就publish(A,msgData),这样就构成了基础的rpc服务
常用接口
//向B服务器发送消息
g.GetServerById(BServerID).Notify(&pb.ReqSend{Name:"我是send消息"})
//向B服务器发送request请求
g.GetServerById(BServerID).Request(&pb.ReqRequest{
Name:"我是request请求",
}, func(resp *pb.RespRequest,err error) {
if err != nil {
return
}
fmt.Println("返回消息:",resp.Name)
})
//向B服务器发送call请求
resp := pb.RespCall{}
err = g.GetServerById(BServerID).Call(&pb.ReqCall{Name:"我是call请求"}, &resp)
if err != nil {
return
}
fmt.Println("返回消息:",resp.Name)
对于send,request和call请求,B服务器需要注册事件处理
//注册send事件handler
s.RegisterServerHandler(func(server rpc.Server, req *pb.ReqSend) {
fmt.Println("收到消息:", req.Name)
})
//注册request事件handler
s.RegisterRequestMsgHandler(func(server rpc.RequestServer, req *pb.ReqRequest) {
resp := &pb.RespRequest{Name:"我是request返回消息"}
server.Answer(resp)
})
//注册call事件handler
s.RegisterRequestMsgHandler(func(server rpc.RequestServer, req *pb.ReqCall) {
resp := &pb.RespCall{Name:"我是call返回消息"}
server.Answer(resp)
})
具体使用方法见example目录下的示例
基于goserver的对战小游戏: http://af.09900990.xyz:5050
小游戏git地址: https://github.com/0990/avatar-fight-server
网友评论