10
votes

Erlang accepte dynamiquement des connexions TCP entrantes

Ce que j'essaie de résoudre: avoir un serveur Erlang TCP qui écoute sur un port spécifique (le code doit résider dans une sorte d'interface / API externe) et chaque connexion entrante doit être gérée par un Gen_Server < / code> (c'est même le gen_tcp: accepter doit être codé à l'intérieur du gen_server ), mais je ne souhaite pas réellement apparaître un nombre prédéfini de processus acceptant une connexion entrante). Est-ce une en quelque sorte possible?


0 commentaires

4 Réponses :


4
votes

Le problème avec gen_tcp: accepter est-il en blocs, donc si vous l'appelez dans un Gen_Server , vous bloquez le serveur de recevoir d'autres messages. Vous pouvez essayer d'éviter cela en passant un délai d'attente, mais cela constitue finalement une forme de scrutin qui est mieux évitée. Au lieu de cela, vous pouvez essayer GEN_NB_SERVER Kevin Smith à la place; Il utilise une fonction interne non documentée prim_inet: async_accept et d'autres prim_inet fonction pour éviter le blocage.


4 commentaires

Mais si je peux comprendre un moyen de relancer le gen_tcp: accepter dans son propre Gen_Server que je ne me soucierais pas qu'il bloque. Mais je suppose qu'il n'est pas possible de savoir d'avance (dire de gen_tcp: écouter ) que vous avez une connexion entrante que vous devez accepter. Merci pour le pointeur de gen_nb_server ! L'avez-vous utilisé en production?


Je ne pense pas que vous ayez besoin de gen_nb_server pour ce que vous faites. Votre cas est vraiment simple.


Je n'ai jamais utilisé gen_nb_server dans la production mais avez utilisé prim_inet: async_accept dans la production.


J'ai recommandé gen_nb_server car la question initiale indiquée gen_server comme exigence. Je suis d'accord en utilisant un processus proc_lib pourrait être meilleur et plus facile; C'est exactement la façon dont nous reproduisons les accepteurs de Yaws .



2
votes

Vous devez utiliser "prim_inet: async_accept (listen_socket, -1)" Comme indiqué par Steve. Maintenant, la connexion entrante serait acceptée par votre raccord de guidon_info (En supposant que votre interface est également un Gen_Server) comme vous avez utilisé une asynchrone Accepter l'appel.

sur l'acceptation de la connexion, vous pouvez frayer un autre ger_server (je recommanderais GEN_FSM) et faites cela comme le "processus de contrôle" en appelant "GEN_TCP: Controling_process (Clisocket, PID du processus SPWned)".

Après que toutes ces données de la prise soient reçues par ce processus plutôt que par votre code d'interface. Comme celui-là un nouveau processus de contrôle serait engendré pour une autre connexion.


4 commentaires

Juste couper et coller d'ailleurs sans attribution.


Oui, je l'ai coupé et collé de ma propre application Erlang. Dois-je prendre la permission de moi-même pour cela?


Désolé, cela ressemblait à un fragment dans une liste de diffusion de la liste de diffusion sur la première vue.


Sa ok peer..vous avait répondu à une question de mienne pour la même application. :)



10
votes

Procédure de base

Vous devez avoir un processus statique (implémenté sous la forme d'un Gen_Server ou d'un processus personnalisé) qui effectue la procédure suivante:

  1. écoute des connexions entrantes à l'aide de gen_tcp: Accepter / 1
  2. Chaque fois qu'il renvoie une connexion, indiquez à un superviseur de frayer un processus de travailleur (par exemple un autre Gen_Server processus)
  3. Obtenez le PID pour ce processus
  4. appelez GEN_TCP: Controling_Process / 2 avec la prise nouvellement retournée et que PID
  5. Envoyez la prise à ce processus

    Remarque: vous doit le faire dans cet ordre, sinon le nouveau processus peut utiliser la prise avant que la propriété ait été remis. Si cela n'est pas terminé, l'ancien processus peut obtenir des messages liés à la prise lorsque le nouveau processus a déjà été repris, ce qui entraîne des paquets abandonnés ou mal manipulés.

    Le processus d'écoute ne devrait avoir qu'une seule responsabilité, et c'est le frai des travailleurs pour de nouvelles connexions. Ce processus bloquera lors de l'appelant Gen_TCP: Accepter / 1 , qui va bien, car les travailleurs démarrés géreront des connexions en cours simultanément. Le blocage d'Accepter Assurez-vous du temps de réponse le plus rapide lorsque de nouvelles connexions sont initiées. Si le processus doit faire d'autres choses comprises entre, gen_tcp: Accepter / 2 pourrait être utilisé avec d'autres actions entrelées entre les délais d'attente.

    Échelle
    • Vous pouvez avoir plusieurs processus en attente avec GEN_TCP: Accepter / 1 sur une seule prise d'écoute, augmenter de plus en plus la concurrence et minimiser la latence d'acceptation.

    • Une autre optimisation serait de prédéfinir des prises pour minimiser davantage la latence après avoir accepté la nouvelle prise.

    • troisième et finale serait de rendre vos processus plus légers en mettant en œuvre les principes de conception OTP dans vos propres processus personnalisés à l'aide de proc_lib ( Plus d'infos ). Cependant, cela ne devrait faire que si vous indiquez de référence et que vous allez en conclure que c'est le comportement gen_server qui vous ralentit.


1 commentaires

Merci, je vais essayer cette approche comme il semble que le plus réalisable



3
votes

Vous voudrez peut-être consulter http://github.com/oscarh/gen_tcpd et utiliser le Manipul_connection Fonction Pour convertir le processus que vous arrivez à un Gen_Server.


0 commentaires