- 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 main
- import (
- "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 clientmgr
- import (
- "github.com/Cyinx/einx"
- "github.com/Cyinx/einx/slog"
- "msg_def"
- )
- type Agent = einx.Agent
- type AgentID = einx.AgentID
- type EventType = einx.EventType
- type Component = einx.Component
- type ComponentID = einx.ComponentID
- type 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 main
- import (
- "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_def
- import (
- "github.com/Cyinx/einx/network"
- "protobuf_gen"
- )
- type VersionCheck = pbgen.VersionCheck
- var 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 = 0
- func 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,"测试")
- }
来源: http://www.tuicool.com/articles/jQnEVz7