[erlang-questions] Re: TCP port sends EXIT message

Alain O'Dea <>
Fri Dec 24 18:10:23 CET 2010


On 2010-12-22, at 7:50, Per Andersson <> wrote:

> Hi!
> 
> On Wed, Dec 15, 2010 at 9:00 PM, Matthias Lang <> 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