[erlang-questions] Re: TCP port sends EXIT message
Alain O'Dea
alain.odea@REDACTED
Fri Dec 24 18:10:23 CET 2010
On 2010-12-22, at 7:50, Per Andersson <avtobiff@REDACTED> wrote:
> Hi!
>
> On Wed, Dec 15, 2010 at 9:00 PM, Matthias Lang <matthias@REDACTED> wrote:
>> On Wednesday, December 15, Per Andersson wrote:
>>
>>> I realized that this happened because the acceptor is shutdown after it
>>> calls controlling_process. I, erroneously, thought that controlling_process
>>> would actually transfer all control and ownership of the socket to a new
>>> process. This does not seem to be the case, the docs state only that the
>>> new owner will receive messages.
>>
>> gen_tcp:controlling_process() transfers both "control" (who receives
>> messages) and "ownership" (which process is linked to the port).
>>
>> I took a guess at what you were trying to do and wrote a minimal,
>> self-contained example that compiles. The socket does not die
>> when the process which originally owned it died:
>
> If I use a similar protocol that you wrote in your example it works
> like a charm.
> I.e. link the processes and put the FSM in a WAIT_FOR_KILL state and then
> send a kill message when the socket is passed to the new process.
>
> I tried just adding a short sleep but the FSM still killed the socket when
> it died. Why?
There is a nice solution to this early in Erlang and OTP in Action http://manning.com/logan for TCP RPC server that uses a gen_server timeout handler to initialize the connection.
You basically need a living owner for the server socket to stay open.
>
>
> Best,
> Per
>
>> -module(per_a).
>> -export([go/0]).
>>
>> go() ->
>> erlang:process_flag(trap_exit, true),
>> {ok, L} = gen_tcp:listen(5555, [{active, false}, {reuseaddr, true}]),
>> spawn(fun connect/0),
>> Self = self(),
>> Acceptor_pid = spawn_link(fun() -> acceptor(L, Self) end),
>> receive
>> {Acceptor_pid, Socket} ->
>> exit(Acceptor_pid, kill),
>> receive
>> {'EXIT', Acceptor_pid, _} -> ok
>> end,
>> io:fwrite("This process is ~p\n", [self()]),
>> io:fwrite("The acceptor pid, ~p is now dead (process_info=~p)\n",
>> [Acceptor_pid, erlang:process_info(Acceptor_pid)]),
>> io:fwrite("The socket is still alive (port_info=~p)\n",
>> [erlang:port_info(Socket)]),
>> {ok, Data} = gen_tcp:recv(Socket, 0),
>> io:fwrite("Here's some freshly received socket data: ~p\n", [Data]),
>> gen_tcp:close(Socket),
>> gen_tcp:close(L)
>> end.
>>
>> connect() ->
>> {ok, S} = gen_tcp:connect(localhost, 5555, []),
>> ok = gen_tcp:send(S, "hello world\n"),
>> Ref = make_ref(), receive Ref -> done end. % hang forever
>>
>> acceptor(L, Parent) ->
>> {ok, S} = gen_tcp:accept(L),
>> ok = gen_tcp:controlling_process(S, Parent),
>> Parent ! {self(), S},
>> Ref = make_ref(), receive Ref -> done end. % hang forever
>>
>> --------------------
>> Here's the output:
>>
>> | 2> per_a:go().
>> | This process is <0.31.0>
>> | The acceptor pid, <0.39.0> is now dead (process_info=undefined)
>> | The socket is still alive (port_info=[{name,"tcp_inet"},
>> | {links,[<0.31.0>]},
>> | {id,2046},
>> | {connected,<0.31.0>},
>> | {input,0},
>> | {output,0}])
>> | Here's some freshly received socket data: "hello world\n"
>> |
>>
>> The question now is: what are you doing differently? Can you post a
>> minimal, self-contained example which compiles, runs and demonstrates
>> the socket dying unexpectedly?
>>
>> Matt
>>
More information about the erlang-questions
mailing list