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.