本篇为实战了,如果有些代码看不懂,或者skynet找不到,请下载demo https://github.com/sundream/ggApp
1.集群
cluster = require "skynet.cluster"
集群间的通讯,是由一个独立的 harbor 服务来完成的。所有的消息包在发送时,skynet 识别出这是一个远程消息包时,都会把它转发到 harbor 服务内。
harbor 服务会建立 tcp 连接到所有它认识的其它 skynet 节点内的 harbor 服务上。
https://blog.codingnow.com/2012/08/skynet_harbor_rpc.html
https://blog.codingnow.com/2017/03/skynet_cluster.html
https://blog.csdn.net/lzb991435344/article/details/77219557
2.组播
播包的分配和释放策略和其它包不同。它需要有引用计数。和别的消息包,发送方分配,接收方释放是不同的。
组播服务并不解决分熟在不同集群节点上的服务归组的问题。即,每个分组内的成员都必须在同一系统进程内。这可以极大的简化设计。用户可以让不同的服务 handle 归属一个组号。向 skynet 索取这个组号对应的 handle 。
向这个组的 handle 发送消息,就等同于向组内所有 handle 发送消息。
3.lua
我们所有的lua服务,均是依附于一个叫snlua的c模块来运行的,lua服务每次收到一个消息,
就会产生一个协程(事实上,skynet每个服务均有一个协程池,lua服务收到消息时,会优先去池子里取一个协程出来,
这里为了理解方便,就视为收到一个消息,就创建一个协程吧),并通过协程执行注册函数,
每个skynet进程在启动时,都会启动一个lua层的launcher服务,该服务主要负责skynet运作期间,服务的创建工作。
我们在lua层创建一个lua层服务时,通常会调用skynet.newservice函数
4.对象管理
local cplayer = class("cplayer",gg.class.cobjevent,gg.class.cobjattrs) //创建一个C对象
local cbag_sys = class("cbag_sys") //创建一个系统
local cbag_item = class("cbag_item") //创建一个道具
--玩家系统
local cplayer = class("cplayer",gg.class.cobjevent,gg.class.cobjattrs)
function cplayer:init(data)
--基类初始化
gg.class.cobjevent.init(self)
gg.class.cobjattrs.init(self,true)
-------------------功能-----------------------
self.bag_sys = gg.class.cbag_sys.new(self,data) --背包系统
end
--背包系统
local cbag_sys = class("cbag_sys")
function cbag_sys:init(player,player_data)
self.player = player
self.bag_items = {}
for _,v in ipairs(player_data.bag_data or {}) do
if v.count>0 and self:get_item_conf(v.id) then
self.bag_items[v.id] = gg.class.cbag_item.new(self,v)
end
end
self.notify_history = {}
self.notify_history_tips = {}
self:init_events() --事件初始化
end
--道具对象
local cbag_item = class("cbag_item")
function cbag_item:init(bag_sys,data)
self.bag_sys = bag_sys
self.id = data.id
self.count = data.count or 0
end
5.继承
local cclient = class("cclient")
local cgate_client = class("cgate_client",gg.class.cclient)
function cgate_client:init()
gg.class.cclient.init(self)--调用父类
end
6.消息包
--解码
local message = global.codec:unpack_message(msg)
--发送一个包给前端 (linktype == "tcp",linktype == "kcp",linktype == "websocket")
skynet.send(linktype,"lua","write",linkobj.linkid,msg)
--发送到其他服务
skynet.send(global:getworldhdl(),"lua","client_message",linkid,msg)
--通过gate转发给前端
function cglobal:sendclient_bylink(linkid,cmd,message)
--编码
local bin = self.codec:pack_message({
cmd = cmd,
args = message,
})
if not bin then
return logger.error("sendclient_bylink encode cmd(%s) error",cmd)
end
skynet.send(self:getgatehdl(),"lua","server_sendlink",linkid,bin)
end
7.数据库
--MySQL
function dispatch_handle.mail_look(session,source,mail_id)
local db = global:getsqldb()
local lock = db:getqueue()
lock(function()
db:update("mail",{state = 1},{Id=mail_id,state=0})
end)
end
--redis
function dispatch_handle.query_plattask_info(session,source,account_id,merchantid)
--redis处理
local db = global:getrsdisdb()
local key = global:getrediskey("task",account_id,merchantid)
--不存在
local data = db:HGETALL(key)
return skynet.retpack(data)
end
8.配置文件
--加载配置加载
function cglobal:loadconf(isreload)
local op = "new"
if isreload then
op = "update"
end
--读取所有配置
local dir = "./config/"
for entry in lfs.dir("./config/") do
if entry ~= '.' and entry ~= '..' and string.find(entry,"%s*.json") then
logger.info("begin load %s config",entry)
local prename = string.split(entry,'.')[1]
local data = gg.load_json(dir,prename)
if data then
sharedata[op](prename,data)
logger.info("end load %s config sucess",entry)
else
logger.info("end load %s config failure",entry)
end
end
end
end
--使用配置文件
function cbag_sys:get_item_conf(id)
local item_conf = sharedata.query("item_config")
if id then
return item_conf[tostring(id)]
end
return item_conf
end