我目前有一个处理来自客户端的多个连接的服务器,以及使用两个连接连接到服务器的客户端。我的客户端有两个进程分别处理与服务器之间的发送和接收,但不能同时处理两者。我目前遇到的问题是,当我想关闭套接字时,我的读取过程卡在gen_tcp:recv/2
块上。如果我设置超时,则在达到超时时将关闭套接字。我的问题是,是否有可能gen_tcp:recv/3
不关闭套接字的呼叫。
这就是我的阅读过程的样子。
read(Socket, Control) ->
Control ! ok,
receive
read ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
%% handling for messages;
Other ->
io:format(Other)
end,
read(self()), %% this sends "read" to itself with "!"
read(Socket, Control);
{error, Reason} ->
io:format(Reason)
end;
close ->
io:format("Closing Reading Socket.~n"),
gen_tcp:close(Socket)
end.
正如你在这里看到的,如果recv/2
不读取任何内容,进程将永远无法收到关闭。
当然,超时设置为 infinity
的gen_tcp:recv/3
不会关闭套接字:)请参阅官方文档。
编辑:
从文档中:
此函数在被动模式下从套接字接收数据包。
查看setopts/2
文档以了解被动模式和主动模式之间的区别。特别:
如果值为 false(被动模式),则进程必须通过调用 gen_tcp:recv/2,3 来显式接收传入数据。
您的进程一次只能做一件事 - 侦听来自另一个进程的关闭消息或等待 TCP 数据包。您可以尝试使用gen_tcp:controlling_process/2
但我不知道细节。另一种解决方案是在单独的(第三个)链接进程中处理recv/3
,并在收到收盘价时终止该进程。
更好的方法是改用活动套接字,请参阅官方文档中的示例部分以获取有关如何执行此操作的一些指南。
在我看来,最好的方法是使用 OTP gen_server
在同一进程中处理close
消息和传入的 TCP 数据包。在 Erlang 和 OTP in Action 一书中有一个关于如何实现它的优秀教程,这里是 Github 上的代码示例。