Un serveur de socket et un serveur de jeux doivent-ils être des processus distincts?


14

Supposons un jeu client / serveur standard simple. Pour le serveur, est-il utile d'avoir un processus distinct qui écoute les connexions et les messages des clients et envoie les données via des sockets locaux ou stdin à un autre processus qui exécute le serveur de jeu réel?

L'autre option consisterait à faire les deux choses en un seul processus. La mise en file d'attente des messages entrants et leur exécution dans le bon ordre ne devrait pas poser de problème d'arrêt.

Je me demande si les ressources supplémentaires pour séparer les deux "activités" en valent vraiment la peine. Comment dois-je décider? J'aimerais entendre tous les avantages / inconvénients.


1
Comment les deux parties communiquent-elles? Des prises?
vz0

Envisagez-vous de changer "l'auditeur" pour utiliser une technique de communication différente, ou d'ajouter des options pour utiliser plus d'un type de communication client-serveur (par exemple si les clients mobiles devaient communiquer de manière différente)? Si tel est le cas, il peut être utile de le séparer afin de pouvoir échanger les modules d'entrée / sortie selon les besoins.
Jon Story

@ JonStory Oui, je le fais. Même avec 2 auditeurs différents, cela pourrait toujours être un processus unique, mais après avoir lu toutes les réponses ici et y avoir réfléchi, j'ai décidé que cela vaudrait la peine d'avoir des processus séparés. Pour ce projet particulier, le client principal sera un navigateur javascript, mais je prévois d'ajouter une application client mobile native à l'avenir.
luleksde

Réponses:


17

Du point de vue de la conception de l'API, lorsque vous décidez de créer plusieurs programmes de communication distincts ou un seul, la question est: chaque programme peut-il fonctionner de manière significative sans les autres? La réponse variera en fonction de votre projet et de vos préférences.

S'ils ne le peuvent pas , cela ne vaut pas la peine d'y penser. De toute évidence, ils sont si étroitement liés qu'ils ne sont pas vraiment des processus distincts.

S'ils le peuvent et que vous pouvez vous imaginer vouloir ajouter différents composants pour les remplacer à l'avenir, une abstraction de processus fournie par le système d'exploitation pourrait vous aider.

Comment bien cela aide dépend du reste de votre pile de technologie bien. Par exemple, Erlang modélise déjà les choses en tant que processus, de sorte que vous ne gagnerez pas beaucoup d'avantages conceptuels en le divisant également en processus OS. À moins que vous ne songiez à réécrire ces parties du serveur dans une langue différente. Les composants internes d'un programme C ++ sont généralement couplés beaucoup plus serrés et donc plus difficiles à échanger, donc les diviser en différents processus de système d'exploitation peut vous faire économiser du travail plus tard si vous pouvez prévoir de tels réarrangements.


11

est-il utile d'avoir un processus distinct qui écoute les connexions et les messages des clients et envoie les données via des sockets locaux ou stdin à un autre processus qui exécute le serveur de jeu réel?

Pour savoir si cela en vaut la peine, vous devez d'abord vous demander quel est le problème que vous essayez de résoudre en ajoutant un service de mise en file d'attente dédié. S'il résout ce problème, cela en vaut la peine; si cela ne résout pas un problème ou si vous n'avez pas de problème à résoudre pour commencer, ce n'est probablement pas le cas.

Voyons quelques raisons pour lesquelles certains serveurs utilisent une architecture à plusieurs niveaux:

  1. Équilibrage de charge - l'équilibrage de charge est judicieux si vous souhaitez répartir votre charge de travail sur plusieurs machines de travail. Si votre programme présente des goulots d'étranglement que vous souhaitez résoudre simplement en ayant plusieurs processus de travail simultanés sur la même machine, il est préférable à long terme de réellement résoudre le goulot d'étranglement, mais comme solution de contournement à court terme, les processus de travail de génération peuvent être pratiques.
  2. Séparation des privilèges - Peut-être que vous ne voulez pas qu'une faille de sécurité dans votre serveur de chat accède automatiquement à votre serveur de jeu ou vice versa. Si votre serveur de jeu est distinct de votre serveur de chat en jeu, vous pouvez configurer votre serveur de jeu et votre serveur de chat pour qu'ils vivent dans un domaine de sécurité distinct (par exemple, exécuter en tant qu'utilisateur différent, avec différents privilèges d'accès, différentes limites de processus, etc.).
  3. Mise à niveau sans interruption de service - si vous souhaitez obtenir une mise à niveau sans interruption de service, vous devez disposer de plusieurs niveaux et configurer le système de sorte que lorsque vous arrêtez un serveur pour maintenance, ses demandes soient redirigées vers les autres serveurs du même niveau pour garantir une continuité un service.
  4. Breaking limit - si vous atteignez la limite de socket, la limite de descripteur de fichier, un verrou d'interpréteur global, etc., vous pourrez peut-être contourner cette limite en exécutant plusieurs processus. Une autre façon de résoudre ce problème est de modifier la limite, mais ce n'est pas toujours facile car vous devrez peut-être recompiler le noyau, ou il peut y avoir des implications en termes de sécurité ou de performances.
  5. Limiter les fuites de ressources - vous voulez écrire des logiciels qui ne fuient pas les ressources, mais même dans des langues entièrement gérées, c'est extrêmement difficile dans des processus de longue durée, et pire c'est difficile à reproduire dans un environnement de développement. Une architecture à plusieurs niveaux vous permet de tuer et de réapparaître les serveurs de jeu après un certain laps de temps ou nombre de demandes pour limiter les dommages causés par les fuites de ressources, sans perturber le service.

5

Je suis d'accord avec le monstre à cliquet. Tant que vous n'avez qu'un seul serveur de jeux, cela ne vaut pas la peine.

Cependant, cette architecture peut s'avérer utile lorsque vous devez évoluer horizontalement. Lorsqu'un serveur de jeux ne suffit plus et que vous devez distribuer votre jeu sur plusieurs serveurs de jeux pour des raisons de performances, l'architecture du "serveur de socket" pourrait très facilement être adaptée pour transformer le serveur de socket en un équilibreur de charge qui achemine automatiquement les connexions vers l'un des nombreux backend serveur.

Mais lorsque vous n'êtes pas sûr d'en avoir besoin, il est probablement trop complexe de développer deux applications serveur distinctes à ce stade.


4

Ce n'est probablement pas le cas, la plupart des langues ont des sockets asynchrones qui vous permettent d'utiliser plusieurs connexions à la fois sans bloquer pendant que les données sont en attente. Cela déplace la partie "socket server" vers le système d'exploitation / noyau.

Avec un serveur de socket explicite, vous encourrez le coût de quelques copies supplémentaires lorsque vous passez les données via le socket local; une chose qui va tuer l'évolutivité est des copies supplémentaires où vous n'en avez pas besoin.


1
À moins que vous ne sachiez déjà que votre serveur aura des exigences d'évolutivité très élevées, je ne m'inquiéterais pas des performances à ce stade. Les frais généraux liés à la copie de certaines données en mémoire sont extrêmement faibles par rapport à ceux de l'envoi de données sur Internet.
Anko
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.