本教程基于libuv库搭建
基本结构
C++结构
netbus:服务器的启动的入口,启动libuv的循环,并附带以下功能:
- 创建缓存区,用于管理内存和内存分配
- 提供TCP和UDP和Websocket的监听入口
- 接收UDP和TCP的数据,并创建好session
- 对TCP的长短包进行处理,并根据包长进行解包,形成完整的单个数据
proto_man:protobuf协议相关,主要负责:
- 对netbus发来的数据进行解包,解出包含stype,ctype,utag,body的包体,根据body的不同,还会形成不同的数据类型,如protobuf为message,Json协议是字符串。
- 对stype,ctype,utag,body数据提供打包函数,形成完整单个数据包发送给Service
service_man:管理服务,各个服务器在此注册服务,并管理各个service,收到消息或断开链接时会调用对应service的函数
service:各个服务的基类,需要实现接收响应函数,断开连接响应函数,连接响应函数
session:保存utag和uid和是否客户端
session_uv:tcp的session,提供链接的管理,保存了对应客户端的handle,并且拥有以下功能:
- 根据protobuf还是websocket来发送打好的数据包
- 关闭连接
- 保存用户ip和端口
udp_session:udp的session,本质上不是链接,保存客户端的ip和端口,拥有发送数据包的功能。
tcp_protocol:给tcp的整包提供读取header的函数,给tcp提供打包函数(前面附上包长)
ws_protocol:websocket相关,提供了握手函数,读取ws的header的函数,mask函数,按照ws的格式发送数据函数
lua导出
日志
支持多参数,多类型
print(str)
Logger.debug(str)
Logger.warning(str)
Logger.error(str)
mysql
Mysql.connect(ip, port, db_name, uname, upwd, on_open_cb)
Mysql.close(conn)
Mysql.query(conn, cmd, on_lua_query_cb)
redis
Redis.connect(ip, port, on_open_cb)
Redis.close_redis(conn)
Redis.query(conn, cmd, on_lua_query_cb)
netbus
Netbus.udp_listen(port)
Netbus.tcp_listen(port)
Netbus.ws_listen(port)
Netbus.tcp_connect(ip, port, on_tcp_connected)
proto_man
stype,ctype,utag = RawCmd.read_header(raw_cmd)
RawCmd.set_utag(raw_cmd)
message = RawCmd.read_body(raw_cmd)
Scheduler
timer = Scheduler.schedule(on_lua_repeat_timer, after_msec, repeat_count, repeat_msec)
timer = Scheduler.once(on_lua_repeat_timer, repeat_msec)
Scheduler.cancel(timer)
Service
Service.register(stype, service)
Service.register_with_raw(stype, service) 直接转发服务
定义Service
function on_logic_recv_cmd(s, msg)
end
end
function on_gateway_disconnect(s, stype)
end
function on_gateway_connect(s, stype)
end
local logic_service = {
on_session_recv_cmd = on_logic_recv_cmd,
on_session_disconnect = on_gateway_disconnect,
on_session_connect = on_gateway_connect
}
session
Session.close(session)
Session.send_msg(session,table(cmd_msg))
Session.send_raw_cmd(session, raw_cmd)
ip,port = Session.get_address(session)
Session.set_utag(session, utag)
utag = Session.get_utag(session)
Session.set_uid(s, uid)
Session.asclient(s, as_client)
Session.udp_send_msg(ip, port, table(cmd_msg))
utils
stamp = Utils.timestamp()
stamp = Utils.timestamp_today()
stamp = Utils.timestamp_yesterday()
通用模块
- 日志模块
- 定时器模块
- 内存分配器模块
- 小内存分配器模块
- 时间戳
业务逻辑
服务器类型
网关服务器:只负责转发数据
用户服务器:处理登录请求,管理用户数据
系统服务器:处理游戏系统的服务,管理游戏数据
逻辑服务器:处理游戏内的同步
流程
每个服务器都有一个main.lua和service.lua,对应一个服务号,其中main.lua主要开启tcp,udp或websocket监听,并注册服务方便接收客户端传过来的对应数据。service.lua主要定义了该服务接收数据后的响应、客户端断开连接后的响应。
具体的业务逻辑通过service.lua进行转发,一个命令号创建一个脚本,编写对应的响应函数。
gateway:需要注册所有服务,因为需要接收所有数据并转发,但注册的时候调用的是register_with_raw,所以不需要解包。另外需要编写一个定时器来检查与其他服务器的连接,当接收到登录请求的时候,需要判断是否已经有人登陆;发送其他数据的时候,判断登录状态(通过uid)。当用户断线的时候,需要对session做清理,并通知所有其他服务器。
authserver:管理用户数据,实现登录,修改用户数据,账号的升级,登出的功能,发送用户数据给客户端。
systemserver:管理游戏大厅数据,实现金币、经验等游戏数据的获取,修改,每日登陆奖励等。
logicserver:
- 管理房间内玩家的数据,实现逻辑服务器的登录,断开链接的响应,进入和退出比赛的响应,与最重要的同步。
- 玩家在该服务器上都有一个player的对象,并用房间类match_mgr来管理一局比赛的玩家,该服务器主要使用面向对象来编程。
- 每个玩家或属于一个房间,或处于游荡状态。当玩家点击匹配的时候会进入房间,当房间满了就开始比赛,同时开启帧同步的定时器。
- logicserver单独监听udp端口,帧同步不走网关,当满足条件时才响应请求。