如果达到超时,gen_tcp:recv/3 是否关闭套接字?

Does gen_tcp:recv/3 closes the socket if the timeout is reached?

我目前有一个服务器处理来自客户端的多个连接,以及使用两个连接连接到服务器的客户端。我的客户端有两个进程分别处理与服务器之间的发送和接收,但不是同时处理这两个进程。我目前遇到的问题是当我想关闭套接字时,我的读取过程卡在了 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 未读取任何内容,该进程将永远无法接收到关闭消息。

当然,超时设置为 infinitygen_tcp:recv/3 不会关闭套接字 :) 请参阅 official documentation.

编辑:

来自文档:

This function receives a packet from a socket in passive mode.

检查 documentation for setopts/2 以了解被动模式和主动模式之间的区别。特别是:

If the value is false (passive mode), the process must explicitly receive incoming data by calling gen_tcp:recv/2,3.

你的进程一次只能做一件事——要么监听来自另一个进程的关闭消息,要么等待 TCP 数据包。您可以尝试使用 gen_tcp:controlling_process/2 但我不知道详细信息。另一种解决方案是在单独的(第三个)链接进程中处理 recv/3 并在收到关闭时终止进程。

更好的方法是改用活动套接字,请参阅 official documentation 中的示例部分,了解如何执行此操作的一些指南。

我认为最好的方法是使用 OTP gen_server 在同一进程中处理 close 消息和传入的 TCP 数据包。 Erlang and OTP in Action book on how to implement that and here is the code example on Github.

中有一个很好的教程