在erlang中中断gen_tcp:recv

Posted

技术标签:

【中文标题】在erlang中中断gen_tcp:recv【英文标题】:Interrupting gen_tcp:recv in erlang 【发布时间】:2016-03-08 16:34:34 【问题描述】:

我们有一个 gen_server 进程,它通过创建被动套接字池并将它们借给其他进程来管理客户端的被动套接字池。任何其他进程都可以借用socket,使用socket向服务器发送请求,通过gen_tcp:recv得到回复,然后将socket释放给gen_server socket pool进程。

套接字池进程监视所有借用套接字的进程。如果任何借用的进程宕机,它会从它那里得到一个宕机信号:

handle_info('DOWN', Ref, process, _Pid, _Reason, State) ->

在这种情况下,我们想清空借用的套接字,并通过放回池中来重用它。问题是,在尝试使用gen_tcp:recv(Socket, 0, 0) 排空套接字时,我们收到inet ealready 错误消息,这意味着recv 操作正在进行中。

所以问题是如何中断之前的recv,成功地清空一个socket,并为其他进程重用。

谢谢。

【问题讨论】:

有趣的是 gen_tcp:recv 的行为方式,我以前从未注意到,但我总是使用活动套接字。我想知道这是否明智,或者就此而言是预期的行为。如果在 gen_tcp recv 上阻塞的进程死了,我真的希望/希望读取被中断,但它会一直保持下去,直到它接收到足够的数据来满足 gen_tcp:recv 调用。您可以考虑使用活动套接字吗?我认为这会更安全,让你做任何 OTP 风格的事情。 听听熟悉 inet 驱动程序 (inet_drv.c) 的人的评论会很有趣吗? 谢谢@Michael,好建议,也会尝试活动套接字 【参考方案1】:

多一层间接性将大大简化情况。

不是将 sockets 传递给需要使用它们的进程,而是让每个套接字由拥有它的单独进程控制,并且 代表 系统内的套接字。根据需要将 Erlang 端消息路由到套接字或从套接字路由以实现套接字的“借用”(更灵活的是,向套接字控制器传递一个使用给定协议的回调模块,因此一旦数据通过网络,它就会被解释为Erlang 内部消息)。

如果这样做,您将不会失去对套接字的控制或使它们处于不确定状态——它们将始终由一个拥有的进程持有。不是让 route-manager/pool-manager 进程接收'DOWN' 消息,而是让套接字控制器监视其当前使用进程。当收到'DOWN' 时,您可以根据需要更改状态。

在一些奇怪的情况下,您可能会发现自己在未指定为所有者的套接字之间传递打开的文件描述符、套接字和其他类型的端口。如果您需要跨多个节点扩展程序,那么传递端口和套接字也会成为一个问题(突然间,您必须关心事物在哪里传递以及它们在哪个节点上等)。

【讨论】:

从技术上讲,我不确定我是否明白这如何解决 OPs 问题。任何“拥有”套接字的进程都可能死掉,虽然任意借用者可能比一个简单的精心制作的套接字中介更有可能死掉,但它仍然可能发生……如果确实如此,套接字将被卡住而没有其他能够接管它的进程... 另外,如果您要将数据转换为消息,使用活动套接字不是更好、更简单,而且还不容易出现接收阻塞问题吗? 感谢zxq9的建议和解释,将尝试实施这种方法。 @Michael - 你是对的,使用主动式套接字可能是一种替代方法,也可以尝试一下,只是听说它比被动式套接字慢,需要在这里做一些比较。 从另一个进程的角度来看,处于活动模式的套接字相当于一个进程。在另一个进程中包装套接字只会增加复制,从而导致性能下降。 @AdamLindberg 普通进程没有控制进程。像这样的池化套接字会使代码的语义复杂化,而具有将套接字作为其控制器表示套接字的真正的进程则不会。性能并不是一切,尤其是当您遇到 OP 所指出的那种编码混乱时。另外:与尝试使用gen_server 处理它们相比,在纯Erlang 中编写控制proc_lib 进程往往会获得更大的性能提升——因此,如果关注套接字事件的响应延迟,那将获得更大的收益。

以上是关于在erlang中中断gen_tcp:recv的主要内容,如果未能解决你的问题,请参考以下文章

Erlang gen_tcp:listen/2 for IPv6

使用 gen_tcp 的 Erlang 客户端-服务器示例未收到任何内容

erlang/elixir gen_tcp connect - 不连接但telnet wil

Erlang OTP 主管 gen_tcp - error,eaddrinuse

寻找一个简单的 ssl erlang 示例

Erlang同时连接1M客户端