2016-04-05 20 views
1

Ich habe einen tcp_listener als gen_server() implementiert. Ich habe eine Funktion namens start_link (Port) erstellt einen tcp_listener an diesem Port. Jetzt habe ich Probleme zu verstehen, wie ich dem tcp_listener sagen kann, dass er aufhört, durch stop() zu hören. Ich habe versucht, eine Funktion wie diese mit Stop aufzurufen.Wie man einen tcp_listener stoppt, der in erlang als gen_server implementiert ist

in der terminate/2-Funktion Ich versuchte, die Abhörbuchse zu schließen, aber fehlgeschlagen.

terminate(_Reason, State = #state{lsocket = LSocket}) -> 
gen_tcp:close(LSocket), 
NewState = State#state{lsocket = null}, 
{ok, NewState}. 

Wenn ich den abhörenden Socket schließe, was passiert mit den akzeptierten Verbindungen, die ich hervorbrachte.

Vielen Dank!

start_link(Port) when is_integer(Port) -> 
    State = #state{port = Port}, 
    gen_server:start_link({local, ?MODULE}, ?MODULE, State, []). 

    init(State = #state{port = Port}) -> 
    io:format("Supervisor started me and I am listening at ~p ~n", [Port]), 
    case gen_tcp:listen(Port, ?TCP_OPTIONS) of 
    {ok, LSocket} -> 
    NewState = State#state{lsocket = LSocket}, 
    spawn(fun() -> accept(NewState) end), 
    {ok, NewState}; 
    {error, Reason} -> 
    {stop, Reason} 
    end. 

    accept(State = #state{lsocket = LSocket}) -> 
    case gen_tcp:accept(LSocket) of 
    {ok, Socket} -> 
    Pid = spawn(fun() -> 
    io:format("Connection accepted ~n"), 
    loop(Socket) 
       end), 
    gen_tcp:controlling_process(Socket, Pid), 
    accept(State); 
    {error, closed} -> error 
    end. 

    loop(Socket) -> 
    case gen_tcp:recv(Socket, 0) of 
     {ok, Data} -> 
     gen_tcp:send(Socket, Data), 
    loop(Socket); 
    {error, closed} -> 
     ok 
    end. 
+0

Sie spawnen keine Verbindung, nur einen Prozess. Wenn Sie den Socket schließen, werden alle Verbindungen gelöscht. Lachst du eigentlich irgendwelche Prozesse? – Amiramix

+0

Ja, ich spawne tatsächlich Prozesse. Wenn ich eine Verbindung annehme, spawne ich einen neuen Prozess. Also später, wenn ich den hörenden Sockel schließe, kann ich mit den akzeptierten Sockeln arbeiten, während ich Nachrichten sende und empfange (in meinem Fall echo_server). Bitte beachten Sie den Code, der jetzt bearbeitet wird. – listen

Antwort

1

empfehle ich Ihnen einen Blick auf this chapter in the Learn You Some Erlang book, insbesondere:

Beide Buchsen Nachrichten auf die gleiche Weise senden, und kann dann mit gen_tcp:close(Socket) geschlossen werden. Beachten Sie, dass das Schließen eines accept-Sockets diesen Socket alleine schließt, und das Schließen eines listen Sockets schließt keine der zugehörigen und etablierten accept-Sockets, sondern unterbricht die gerade laufenden akzeptierten Aufrufe durch die Rückgabe von {error, closed}.

So sollte es nur eine Frage des Aufrufs gen_tcp:close(Socket) auf allen Sockets sein.

+1

danke amiramix. Macht jetzt Sinn. Wie wäre es, alle akzeptierten Sockets als Teil des Status zu speichern und dann alle diese Sockets zu schließen, wenn stop() aufgerufen wird. Ist das ein schlechter Ansatz? – listen

+1

Nein, überhaupt nicht, sie müssen aber im Zustand entweder des Elternteils oder jedes Kindes gespeichert werden. Vergessen Sie nicht, dass sobald der Socket geschlossen ist und ein Prozess versucht ihn zu benutzen, ein Fehler auftritt, den Sie verarbeiten müssen. – Amiramix

+0

Danke! Ich implementierte als ETS-Tabelle, nicht ein Teil des Staates, der alle verbundenen Sockets speichert und dann jeden von ihnen schließt. – listen