Erlang: избежание состояния гонки с gen tcp:процесс управления
я реализую простой tcp-сервер со следующей последовательностью:
{ok, LS} = gen_tcp:listen(Port,[{active, true}, {reuseaddr, true}, {mode, list}]),
{ok, Socket} = gen_tcp:accept(LS),
Pid = spawn_link(M, F, [Socket]),
gen_tcp:controlling_process(Socket, Pid)
использование опции {active, true} может вызвать условие гонки, когда новый пакет поступает в процесс сокета до вызова "controlling_process", что приведет к сообщению {tcp,Socket, Data}, поступающему в отцовский процесс вместо дочернего.
как этого можно избежать ?
2 ответов
вы правы. В таких случаях вам обязательно нужно {active, false}
передано среди параметров прослушивания сокета. Рассмотрим этот фрагмент кода:
-define(TCP_OPTIONS, [binary, {active, false}, ...]).
...
start(Port) ->
{ok, Socket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
accept(Socket).
accept(ListenSocket) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
Pid = spawn(fun() ->
io:format("Connection accepted ~n", []),
enter_loop(Socket)
end),
gen_tcp:controlling_process(Socket, Pid),
Pid ! ack,
accept(ListenSocket);
Error ->
exit(Error)
end.
enter_loop(Sock) ->
%% make sure to acknowledge owner rights transmission finished
receive ack -> ok end,
loop(Sock).
loop(Sock) ->
%% set soscket options to receive messages directly into itself
inet:setopts(Sock, [{active, once}]),
receive
{tcp, Socket, Data} ->
io:format("Got packet: ~p~n", [Data]),
...,
loop(Socket);
{tcp_closed, Socket} ->
io:format("Socket ~p closed~n", [Socket]);
{tcp_error, Socket, Reason} ->
io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])
end.
таким образом, вы ничего не потеряли до controlling_process
успешно. Это известная проблема, которая много обсуждалась в интернете.
Если вы хотите использовать решение ready to go, вам обязательно нужно взглянуть на Ранч.
Если сокет активен,inet:tcp_controlling_process
(называемых gen_tcp:controlling_process
) устанавливает сокет в пассивный, затем выборочно получает все сообщения, связанные с этим сокетом, и отправляет их новому владельцу, эффективно перемещая их в очередь сообщений нового владельца. Затем он восстанавливает сокет в active.
таким образом, нет никакого условия гонки: они уже подумали об этом и исправили его в библиотеке.