2016-01-21 31 views
2

我有一个“主机”的静态列表及其信息,以及“主机代理”的动态列表。只要通过TCP连接连接到服务器,每台主机都有且仅有一个代理。由于主机可能连接也可能不连接,因此其代理进程可能启动也可能不启动。当一个TCP包与主机ID一起到达时,我需要知道这个主机的“代理”是否启动。如何跟踪erlang中的子进程?

连接负责接收和发送来自TCP套接字的数据,解析数据以找出它应该发送给哪个主机并传递给它的主机代理来处理。

主机保留主机信息。主机代理处理传入数据,将主机信息保存到主机,并决定以什么格式发送(例如,使用主机ID和响应代码对客户端进行确认)。

而在数据包中,它指定了源主机和目标主机,这意味着它由源主机发送并应由目标主机接收。在这种情况下,目标主机可以连接到另一个连接。这就是为什么需要全局连接的global为了方便获取目标主机代理pid。

我有一个监督树,其中host_supervisor监视所有的host,并connection_supervisor监控每个connectionhost_agent_supervisor显示器agenthost_supervisor,connection_supervisor都是由申请主管监督的,这意味着他们是监督树中的一级子女。但host_agent_supervisorconnection_supervisor之下。

问题:

  1. 是它存储的地图与HOST_ID和 host_agent_pid对DB是一个好主意?
  2. 如果1.为真,如何更新host_agent_pid 当出现错误和代理程序已重新启动?
  3. 有没有更好的主意来实施这种情况?看来我的解决方案不符合“erlang的方式”。

回答

1

为了获得主管的子进程列表,您可以使用supervisor:which_children/1 API。它会获得对您的主管的引用,该主管可以是其注册名称或PID,并返回其子代的列表。

supervisor:which_children(SupRef) -> [{Id, Child, Type, Modules}] 
+0

特定于我的使用案例,我需要检查所有连接上的所有host_agent_sup以查找是否存在相对的主机代理。这似乎有点复杂。有没有更好的解决方案来解决这种情况? – gy8409

+0

@ gy8409同样使用地图来追踪复杂场景中的特殊过程并不是一个坏习惯。这张地图可以位于协调员进程或ets表的状态中。 –

3

简单的,或快速解答您的问题(S)是:

  1. 这很好,但除了一张地图,你也可以使用gb_trees,字典或ETS表(地图是当然最不成熟的)。但是,尽管如此,PID查找表的关键/ ID原则上是好的。 ETS可能会带来比其他过程更好的性能优势,因为您可以创建可从其他过程访问的ETS表,从而消除了单个过程执行所有读写操作的必要性。这可能或可能不重要和/或适当。

  2. 一个简单的方法就是每次启动一个“主代理”时,它会产生另一个进程,除了链接到“主代理”并将主代号从任何存储中删除当“主机代理”死亡时。另一种方法是使映射存储过程本身链接到您的主机代理程序PID,这可能会减少您对可能的竞争条件的关注。

  3. 可能。当我读到你的问题时,我留下了一些问题和一般感觉,我会选择的解决方案不会导致我所查询的确切查询问题(即在收到以下内容时查找“主代理”的PID)一个TCP数据包),但我不能确定这不是因为你已经努力最大限度地减少堆栈溢出的问题。对于我来说,“主机”,“主机代理”和“连接”过程的角色,责任和相互作用究竟是什么,以及它们是否应该全部存在和/或是否具有单独的监督树,有点不清楚。

所以,看可能的选择。当你说“当一个TCP数据包到达”我想,当一个国外主机连接到监听套接字或发送已经接受现有的插座上的一些数据,你的意思是,并且主机ID是主机名(或端口),或者是外部主机在连接后发送给您的任意其他ID。

无论哪种方式...通常在这种情况下,我期望一个新的进程(通过它的声音的“主机代理”)将被派生来处理新建立的TCP连接(通过一个动态的(例如简单的一对一的管理者),获得作为该连接的服务器端端点的套接字的所有权;根据需要读取和写入套接字,并在连接关闭时终止。

使用该模型时,如果已经建立连接,则始终应启动“主代理”,并且如果没有连接,则始终不启动,并且任何传入的TCP数据包将自动终止于正确的代理,因为它将被传递到代理正在处理的套接字,或者如果它是新连接,代理将启动。

现在从不会出现在收到TCP数据包时查找代理的PID的需要。

如果因为其他原因需要查找代理的PID,因为说服务器有时需要主动向可能连接的“主机”发送数据,那么您必须获取所有监督的列表“主持人代理人”并挑选出正确的人(为此,你可以使用主管:which_children/1,根据Hamidreza的回答)或者你可以使用map,gb_trees,dict,ets等来维护主机ID到PID的映射。这是正确的取决于你可以拥有多少“主机” - 如果它不止一个,那么你应该保留一个某种类型的地图,以便查找时间不会变得太大。

最后的评论,如果你还没有,可以考虑看gproc,以防你认为它适合你的情况。它做这种事情。

编辑/添加(以下问题编辑):

你的连接过程听起来多余的给我;如上所述,如果您将套接字指定给主机代理,那么连接的大部分责任都将消失。主机代理没有理由不能解析它接收到的数据,就我所见,让另一个进程解析它并没有任何价值,只是将它传递给另一个进程。解析本身可能是一个确定性函数,所以对它有一个单独的模块是明智的,但我认为在单独的过程中没有意义。

我没有看到你的'主机'进程的重点,你说“主机保留主机信息”,这听起来像它只是一个持有主机名或主机ID的过程,类似的东西?

你也说“它指定了源主机和目标主机,这意味着它由源主机发送,应该由目标主机接收”,它开始使这个声音有点像聊天服务器,或者至少某种hub spoke/star network风格的通信协议。我不明白为什么你不能做你想要的一切,通过创建监督树这样会:

 top_sup 
      | 
    .------------------------------. 
    |    |    | 
map_server svc_listener  hosts_sup (simple one to one) 
            | 
         .-----------------------------> 
         | | | | | | 

这里的“map_server”只是维持映射主机ID到hosts PID的一个时, svc_listener具有监听套接字,并且只接受连接并要求hosts_sup在新客户端连接时产生新的host,并且host进程(在hosts_sup之下)负责接受的套接字,并将主机ID及其PID注册为map_server他们开始。

如果map_server链接到host的PID它能自动清理时host死亡,并且它可以用于任何过程由主机ID来查找一个host PID提供一个合适的API。

+0

我重新说明了我的问题,使其更清楚。 – gy8409