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

Matthias Lang matthias@REDACTED
Wed Dec 15 21:00:15 CET 2010


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:

-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