对您的问题的简单或快速回答是:
没关系,不过除了地图之外,您还可以使用 gb_trees、dict 或 ETS 表(当然,地图是所有这些中最不成熟的)。然而,尽管如此,PID 查找表的键/ID 原则上是可以的。 ETS 可能会比其他进程带来性能优势,因为您可以创建一个可以从其他进程访问的 ETS 表,从而消除了单个进程执行所有读取和写入的必要性。这可能重要也可能不重要和/或适当。
执行此操作的一种简单方法是,每次“主机代理”启动时,它都会生成另一个进程,该进程除了链接到“主机代理”并从任何存储中删除主机 ID 到代理 PID 映射之外什么都不做当“主机代理”死亡时,您就有了。另一种方法是使映射存储进程本身链接到您的主机代理 PID,这可能会让您减少对可能的竞争条件的关注。
-
可能。当我阅读您的问题时,我留下了某些问题,并且普遍认为我选择的解决方案不会引导我找到您所询问的精确查找问题(即在收到“主机代理”的 PID 时查找TCP 数据包),但我不能确定这不是因为您已经努力将您对 Stack Overflow 的问题最小化。我有点不清楚您的“主机”、“主机代理”和“连接”进程的角色、职责和交互到底是什么,以及它们是否都应该存在和/或有单独的监督树。
所以,寻找可能的替代方案...当您说“当 TCP 数据包到达时”时,我假设您的意思是当外部主机连接到侦听套接字或在已接受的现有套接字上发送一些数据时,并且主机ID 可以是主机名(和/或端口),也可以是外部主机在连接后发送给您的其他任意 ID。
无论哪种方式...通常在这种情况下,我希望会产生一个新进程(在您的情况下是“主机代理”)来处理新建立的 TCP 连接(通过一个动态的(例如简单的一对一的)监督者),取得作为该连接的服务器端端点的套接字的所有权;根据需要读写套接字,并在连接关闭时终止。
使用该模型,如果已经有连接,则应始终启动“主机代理”,如果没有连接,则始终不启动,并且任何传入的 TCP 数据包将自动落入正确的代理手中,因为它将被传递到代理正在处理的套接字,或者如果它是一个新连接,代理将被启动。
现在不再需要在收到 TCP 数据包时查找代理的 PID。
如果您出于其他原因需要查找代理的 PID,因为假设您的服务器有时需要主动向可能连接的“主机”发送数据,那么您要么必须获取所有受监管的列表“主机代理”并选择正确的代理(为此,您将使用 supervisor:which_children/1,根据 Hamidreza 的回答)或者您将使用 map、gb_trees、dict、ets 等维护主机 ID 到 PID 的映射。是否正确取决于您可以拥有多少“主机” - 如果它不止少数,那么您可能应该维护某种地图,以便查找时间不会变得太大。
最后的评论,如果你还没有考虑过gproc,你可以考虑看看,以防你认为它对你的情况有用。它会做这种事情。
编辑/添加(在问题编辑之后):
你的连接过程对我来说是多余的;如上所述,如果您将套接字提供给主机代理,那么连接的大部分责任就消失了。主机代理没有理由无法解析它接收到的数据,据我所知,让另一个进程解析它没有任何价值,然后将它传递给另一个进程。解析本身可能是一个确定性函数,因此为它设置一个单独的模块是明智的,但我认为单独的过程没有意义。
我不明白你的“主机”进程的意义,你说“主机保留主机信息”,这听起来像是一个持有主机名或主机 ID 的进程,诸如此类?
你还说“它指定了源主机和目标主机,这意味着它是由源主机发送的,应该由目标主机接收”,这开始让这听起来有点像聊天服务器,或者至少是某种@ 987654321@风格的通讯协议。我不明白为什么你不能通过创建这样的主管树来做你想做的一切:
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 死亡时自动清理,并且它可以为任何进程提供合适的API,以通过主机ID 查找host PID。