skynet框架 源码分析 四

本章主要讲解: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文件,启动一个测试组播的服务。让我们来读源码:

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. local skynet = require "skynet"  
  2. local group = require "mcgroup"  
  3.   
  4. skynet.start(function()  
  5.     local gid = group.create()  
  6.     local gaddr = group.address(gid)  
  7.     local g = {}  
  8.     print("=== Create Group ===",gid,skynet.address(gaddr))  
  9.     for i=1,10 do  
  10.         local address = skynet.newservice("testgroup_c", tostring(i))  
  11.         table.insert(g, address)  
  12.         group.enter(gid , address)  
  13.     end  
  14.     skynet.cast(g,"text","Cast")  
  15.     skynet.sleep(1000)  
  16.     skynet.send(gaddr,"text","Hello World")  
  17.     skynet.exit()  
  18. 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在干什么。

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. function group.enter(id, handle)  
  2.     handle = handle or skynet.self()  
  3.     skynet.send(SERVICE, "lua" , "ENTER", handle, id)  
  4. end  

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

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. -- 为某个harbor上创建接收服务,并将其添加到其他harbor上,  
  2. -- 同时将别的harbor上的接受该广播组的服务添加到本harbor上  
  3. local function create_group_in(harbor, id)    
  4.     local group_agent = assert(harbor_ctrl[harbor])  
  5.     local g = multicast[id]  
  6.     g[harbor] = false     
  7.     -- 在某个harbor上创建这个组的接受服务  
  8.     local receive_group_addr = skynet.call(group_agent, "lua", "CREATE", id)  
  9.     -- 向将别的组的接收地址注册到本组管理器中  
  10.     for _,mc in pairs(g) do  
  11.         if mc then            
  12.             skynet.send(group_agent, "lua", "AGENT", id, mc)  
  13.         end  
  14.     end  
  15.     -- 向别的组发送当前接收组的地址  
  16.     for harbor_id, f_group_agent in pairs(harbor_ctrl) do  
  17.         if harbor_id ~= harbor then  
  18.             skynet.send(f_group_agent, "lua", "AGENT", id, receive_group_addr  
  19.         end  
  20.     end  
  21.     -- g跟组id值有关系,全都是各个harbor的接收组地址  
  22.     -- 一个组有一个g(multicast[id])表,g表中 harbor_id = 组(第id个组的地址)接收组地址  
  23.     g[harbor] = receive_group_addr    
  24. end  
  25.   
  26. function command.ENTER(address, harbor, id)  
  27.     local g = multicast[id]  
  28.     assert(g,id)  
  29.     if g[harbor] == nil then  
  30.         create_group_in(harbor, id)  
  31.     end  
  32.     local group_agent = assert(harbor_ctrl[harbor])  
  33.   
  34.     skynet.send(group_agent, "lua", "ENTER", id, address)  
  35. 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服务。而后,简单的看下一下面这句源码

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. skynet.send(gaddr,"text","Hello World")  

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值