Gen_tcp:recv/3 закрывает сокет, если время ожидания истекло?

В настоящее время у меня есть сервер, который обрабатывает несколько подключений от клиентов, и клиент, который подключается к серверу, используя два подключения. Мой клиент имеет два процесса, которые обрабатывают соответственно отправку и получение на сервер и с сервера, но не оба одновременно. Проблема, с которой я столкнулся в настоящее время, заключается в том, что когда я хочу закрыть сокет, мой процесс чтения зависает 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 ничего не читает

1 ответ

Решение

Конечно, gen_tcp:recv/3 с установленным таймаутом infinity не закроем розетку:) Смотрите официальную документацию.

Редактировать:

Из документации:

Эта функция получает пакет от сокета в пассивном режиме.

Проверьте документацию для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.

Другие вопросы по тегам