einx: 一个用Go构建的游戏服务器

84 阅读2分钟
原文链接: click.aliyun.com

einx

a framework in golang for game server or app server.

a example server for einx (https://github.com/Cyinx/game_server_einx)

einx 是一个由 golang 编写的用于游戏服务器或者应用服务器的开源框架。

设计核心:

 ●  模块与组件的组合机制,模块是逻辑核心。
 ●  lua脚本
 ●  按业务分离逻辑
 ●  einx/db 组件化数据库相关操作
 ●  einx/network 组件化网络IO,目前只支持TCP
 ●  einx/log 异步日志库
 ●  einx/timer 时间轮定时器
 ●  einx/module 模块
 ●  einx/component 组件

 ●  einx/lua 脚本相关操作

模块与组件

每个模块有且仅有一个goroutine用于处理被投递到本模块中的消息,在模块中的逻辑不需要考虑同步问题,简化了逻辑开发难度,模块与模块之间可以通过RPC交互

使用 einx 搭建一个简单的服务器

首先安装 einx

git clone https://github.com/Cyinx/einx.git

创建一个简单的einx例子:

package mainimport ( "github.com/Cyinx/einx" "github.com/Cyinx/einx/slog")func main() { slog.SetLogPath("log/game_server/") slog.LogInfo("game_server", "start server...") slog.LogInfo("game_server", "hello world...") einx.Run() einx.Close() }

einx的核心是module,module中可以添加各种component作为组件:

Cyinx/einx/network 网络相关的component Cyinx/einx/db 数据库相关的component

创建一个TCPServer的component管理器:

package clientmgrimport ( "github.com/Cyinx/einx" "github.com/Cyinx/einx/slog" "msg_def")type Agent = einx.Agenttype AgentID = einx.AgentIDtype EventType = einx.EventTypetype Component = einx.Componenttype ComponentID = einx.ComponentIDtype ClientMgr struct { client_map map[AgentID]Agent tcp_link Component}var Instance = &ClientMgr{ client_map: make(map[AgentID]Agent), }func (this *ClientMgr) GetClient(agent_id AgentID) (Agent, bool) { client, ok := this.client_map[agent_id] return client, ok }func (this *ClientMgr) OnLinkerConneted(id AgentID, agent Agent) { this.client_map[id] = agent //新连接连入服务器}func (this *ClientMgr) OnLinkerClosed(id AgentID, agent Agent) { delete(this.client_map, id) //连接断开}func (this *ClientMgr) OnComponentError(c Component, err error) { }func (this *ClientMgr) OnComponentCreate(id ComponentID, component Component) { this.tcp_link = component component.Start() slog.LogInfo("tcp", "Tcp sever start success") }

创建一个逻辑module,并将TcpServer管理器加入到module之中,服务器就可以启动,并监听2345端口的请求

package mainimport ( "clientmgr" "github.com/Cyinx/einx" "github.com/Cyinx/einx/slog")var logic = einx.GetModule("logic")func main() { slog.SetLogPath("log/game_server/") logic.AddTcpServer(":2345", clientmgr.Instance) slog.LogInfo("game_server", "start server...") einx.Run() einx.Close() }

注册消息handler与Rpc: 注册消息handler需要事先注册一个Message:

package msg_defimport ( "github.com/Cyinx/einx/network" "protobuf_gen")type VersionCheck = pbgen.VersionCheckvar VersionCheckMsgID = network.RegisterMsgProto(uint16(pbgen.MainMsgID_GENERAL_MSG), uint16(pbgen.HandlerMsgID_VERSION_CHECK), (*VersionCheck)(nil))

在注册RPC时,使用字符串作为RPC名,注册handler时,需要使用之前注册的MsgID

import ( "msg_def")var logic = einx.GetModule("logic")func InitDBHandler() { logic.RegisterRpcHandler("testRpc", testRpc) logic.RegisterHandler(msg_def.VersionCheckMsgID, CheckVersion) }func testRpc(sender interface{}, args []interface{}) { }func CheckVersion(agent Agent, args interface{}) { version_check_msg := args.(*msg_def.VersionCheck) }

注册定时器使用module.AddTimer函数,返回值为timerID,如果要提前停止timer,可以执行module.RemoveTimer(timerid):

import ( "msg_def")var logic = einx.GetModule("logic")var testTimerID uint64 = 0func InitDBHandler() { logic.RegisterRpcHandler("testRpc", testRpc) logic.RegisterHandler(msg_def.VersionCheckMsgID, CheckVersion) }func testRpc(sender interface{}, args []interface{}) { if testTimerID != 0 { logic.RemoveTimer(testTimerID) } }func TestTimer(args []interface{}) { testTimerID = 0}func CheckVersion(agent Agent, args interface{}) { version_check_msg := args.(*msg_def.VersionCheck) testTimerID = logic.AddTimer(1000,TestTimer,1,2,"测试") }
原文发布时间为:2018-10-29 本文作者:Cyinx 本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“ Golang语言社区”。