skynet框架 源码分析 四

原创 2013年12月12日 19:39:54



        本章主要讲解:skynet的组播服务是怎么发生的,如何运用。

        组播这个过程主要涉及了以下几个服务。
        group_mgr,group_agent,multicast,tunnel,localcast。

        group_mgr是每个服务器集群只有一个(即多个进程共有一个)。
        group_agent是每个harbor(即一个进程)只有一个。
        multicast。每次组播过程会生成两个multicast服务,一个服务用来发送消息(接下来称其为send服务),一个服务用来接受来自其他harbor的消息(接下来称其为recv服务)。这两个服务中,组员大体相同,不过,send服务比recv服务多一些成员,send组中有额外的tunnel服务成员。图解:


        tunnel是一个记录别的harbor上recv服务的服务。例如,假如有一个组ID为10,在harbor1上有一个组员,在harbor2上有一个组员,那么会在harbor1上生成一个tunnel服务指向harbor2上的组ID为10的recv组服务。这样在harbor1上给组10发广播的时候,harbor2的成员也能收到消息。

        运行service文件夹下的testgroup.lua文件,启动一个测试组播的服务。让我们来读源码:

local skynet = require "skynet"
local group = require "mcgroup"

skynet.start(function()
	local gid = group.create()
	local gaddr = group.address(gid)
	local g = {}
	print("=== Create Group ===",gid,skynet.address(gaddr))
	for i=1,10 do
		local address = skynet.newservice("testgroup_c", tostring(i))
		table.insert(g, address)
		group.enter(gid , address)
	end
	skynet.cast(g,"text","Cast")
	skynet.sleep(1000)
	skynet.send(gaddr,"text","Hello World")
	skynet.exit()
end)

        首先,引入mcgroup库。mcgroup,库会启动全局组播服务group_mgr,和本harbor的group_agent服务。
        group.create会向group_mgr申请一个组号ID(此文假设其为A组)
        group.address是获取ID组的发送服务地址,在这里面会生成一个multicast服务,也就是send服务,并将send服务的handle赋值gaddr。
        for循环中,开启了10个组播模拟服务,这个我就不解释了。看一下group.enter在干什么。

function group.enter(id, handle)
	handle = handle or skynet.self()
	skynet.send(SERVICE, "lua" , "ENTER", handle, id)
end

        向全局group_mgr发送进入某个组的请求。也就是将生成的testgroup_c服务添加到A组的send服务中。不过在此过程中继续看group_mgr的源码。

-- 为某个harbor上创建接收服务,并将其添加到其他harbor上,
-- 同时将别的harbor上的接受该广播组的服务添加到本harbor上
local function create_group_in(harbor, id)	
	local group_agent = assert(harbor_ctrl[harbor])
	local g = multicast[id]
	g[harbor] = false	
	-- 在某个harbor上创建这个组的接受服务
	local receive_group_addr = skynet.call(group_agent, "lua", "CREATE", id)
	-- 向将别的组的接收地址注册到本组管理器中
	for _,mc in pairs(g) do
		if mc then			
			skynet.send(group_agent, "lua", "AGENT", id, mc)
		end
	end
	-- 向别的组发送当前接收组的地址
	for harbor_id, f_group_agent in pairs(harbor_ctrl) do
		if harbor_id ~= harbor then
			skynet.send(f_group_agent, "lua", "AGENT", id, receive_group_addr
		end
	end
	-- g跟组id值有关系,全都是各个harbor的接收组地址
	-- 一个组有一个g(multicast[id])表,g表中 harbor_id = 组(第id个组的地址)接收组地址
	g[harbor] = receive_group_addr	
end

function command.ENTER(address, harbor, id)
	local g = multicast[id]
	assert(g,id)
	if g[harbor] == nil then
		create_group_in(harbor, id)
	end
	local group_agent = assert(harbor_ctrl[harbor])

	skynet.send(group_agent, "lua", "ENTER", id, address)
end

        首先,我们把当前harbor命名为harbor1,把其他的harbor命名为harborN。

        开始读代码。在group_mgr的ENTER接口中,做了两件事情,第一件:将自己的recv服务通过另外一个的harbor(称其为harbor2)的group_agent,添加到harbor2上。在harbor2上是如何做到的呢。我们继续读代码,发现harbor2上的group_agent在收到消息后,会为A组生成一个并生成一个tunnel服务指向harbor1上的recv服务,而后将tunnel添加到A组关联的send服务,若在harbor2上没有send服务,就生成一个;第二件事:就是将当前的testgroup_c服务添加到本harbor的send服务和recv服务中。(这其中会有一个问题,加入harbor2上没有A组的成员,我觉得就没办法在harbor2上想A组发送广播消息。)

        在经过这以后,我们获得了两个组播服务,分别是recv服务,和send服务。而后,简单的看下一下面这句源码

skynet.send(gaddr,"text","Hello World")

        其实就是像send服务发送一条广播消息,hello world。









云风skynet服务端框架研究

http://forthxu.com/blog/skynet.html skynet是云风编写的服务端底层管理框架,底层由C编写,配套lua作为脚本使用,可换python等其他脚本语言。...
  • oMingZi12345678
  • oMingZi12345678
  • 2015年12月10日 13:44
  • 7360

Skynet服务器框架(一) Linux下的安装和启动

简介:Skynet主要工作是管理注册服务,并开启多线程协调服务之间的调用和通讯。框架核心:根据作者的描述,Skynet的核心功能就是解决一个问题: 把一个符合规范的C模块,从动态库(so文件)中启动...
  • linshuhe1
  • linshuhe1
  • 2017年04月13日 19:20
  • 3669

skynet框架 使用心得

使用skynet将线上的项目重写一遍之后,没上线之前我想说,sky n
  • a240581469
  • a240581469
  • 2014年09月14日 14:34
  • 10671

Skynet服务器框架(四) Lua服务创建和启动剖析

前言:之前从Skynet启动过程,解读了skynet的启动部分C语言编写的底层源码,最后成功启动了引导的lua服务bootstrap.lua,接下来我们要尝试自定义一个lua服务,并让它启动起来。bo...
  • linshuhe1
  • linshuhe1
  • 2017年04月17日 14:13
  • 2827

skynet框架 源码分析 三

今天我们来读service_lua.c文件。        这个文件很重要,它是模块snlua的源文件,也是各个lua服务节点的制造者。比如:agent服务节点,watchdog服务节点,launch...
  • a240581469
  • a240581469
  • 2013年12月08日 16:45
  • 10311

Skynet服务器框架(六) Socket服务源码剖析和应用

引言: 如何在skynet框架中使用socket+protobuf。上篇 Skynet服务器框架(五) 使用pbc(protobuf) 我们已经大致了解了如何在Skynet中通过pcb来使用Pr...
  • linshuhe1
  • linshuhe1
  • 2017年05月22日 19:43
  • 2227

skynet框架 源码分析 一

本人所看的skynet框架,是云风所写的开源分布式服务器系统。        说说广泛流传的分布式系统,我觉得最简单的理解就是,一个服务器系统可以开很多进程来完成任务,并且这些进程可以不受地域的限制,...
  • a240581469
  • a240581469
  • 2013年12月06日 18:13
  • 14499

Skynet服务器框架(二) C源码剖析启动流程

前言:最近因为要帮别人做一个Mac和Windows平台下都使用的桌面应用,功能很简单,就是一个文本编辑器,所以大致了解了一下跨平台桌面应用开发的框架,知乎上推荐多半是 Electron 和 NW.js...
  • linshuhe1
  • linshuhe1
  • 2017年04月15日 15:15
  • 4301

skynet框架 源码分析 三

今天我们来读service_lua.c文件。        这个文件很重要,它是模块snlua的源文件,也是各个lua服务节点的制造者。比如:agent服务节点,watchdog服务节点,lau...
  • linking530
  • linking530
  • 2016年10月09日 12:54
  • 437

Skynet服务器框架(二) C源码剖析启动流程

前言:最近因为要帮别人做一个Mac和Windows平台下都使用的桌面应用,功能很简单,就是一个文本编辑器,所以大致了解了一下跨平台桌面应用开发的框架,知乎上推荐多半是 Electron 和 NW.js...
  • linshuhe1
  • linshuhe1
  • 2017年04月15日 15:15
  • 4301
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:skynet框架 源码分析 四
举报原因:
原因补充:

(最多只允许输入30个字)