2016-04-05 2 views
1

J'ai implémenté un tcp_listener en tant que gen_server(). J'ai une fonction appelée start_link (Port) crée un tcp_listener sur ce port. Maintenant, j'ai du mal à comprendre comment dire au tcp_listener d'arrêter d'écouter via stop(). J'ai essayé d'appeler une fonction comme celle-ci avec stop. Dans la fonction terminate/2, j'ai essayé de fermer la prise d'écoute, mais j'ai échoué.Comment arrêter un tcp_listener implémenté en tant que serveur_gen dans erlang

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

Si je ferme la prise d'écoute, qu'advient-il des connexions acceptées que j'ai générées.

Merci!

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

Vous ne créez pas de connexion, mais seulement un processus. Si vous fermez la prise, toutes les connexions seront supprimées. Êtes-vous réellement engendrer des processus? – Amiramix

+0

Oui, je suis en fait un processus de ponte. Si j'accepte une connexion, je lance un nouveau processus. Donc plus tard même si je ferme la prise d'écoute, je suis capable de travailler avec les sockets acceptées car j'envoie et reçoit des messages (echo_server, dans mon cas). S'il vous plaît se référer au code, édité maintenant. – listen

Répondre

1

je vous recommande de jeter un oeil à this chapter in the Learn You Some Erlang book, notamment:

Les deux prises peuvent envoyer des messages de la même manière, et peut alors être fermé par gen_tcp:close(Socket). Notez que la fermeture d'un socket accept fermera ce socket seul, et la fermeture d'un socket listen ne fermera aucun des socket accept liés et établis, mais interrompra les appels d'acceptation en cours en retournant {error, closed}.

Donc, il devrait être juste une question d'appeler gen_tcp:close(Socket) sur toutes les sockets.

+1

merci amiramix. Ça a du sens maintenant. que diriez-vous de stocker toutes les sockets acceptées dans le cadre de l'état, puis de fermer tous ces sockets lorsque stop() est appelé. Est-ce une mauvaise approche? – listen

+1

Non, pas du tout, ils doivent être stockés dans l'état du parent ou de chaque enfant. N'oubliez pas qu'une fois que le socket est fermé et qu'un processus essaie de l'utiliser, il va avoir une erreur, que vous devez pouvoir gérer. – Amiramix

+0

Merci! J'ai implémenté comme une table ets, pas une partie de l'état, qui stocke toutes les sockets connectés et puis fermez chacun d'eux. – listen