Question Serveur de jeu PHP, plusieurs clients TCP?


Je fais un jeu multijoueur basé sur un navigateur Web. J'ai déterminé que les websockets sont le meilleur moyen de gérer les communications en raison de leur nature en temps réel. Le client utilise un canevas HTML5 pour rendre le jeu et les websockets pour communiquer avec l'hôte.

J'ai choisi d'utiliser PHP pour héberger le jeu car il semble être préféré par les fournisseurs d'hébergement. Je n'ai jamais utilisé PHP auparavant, mais j'ai fait des choses similaires avec les websockets en Java, mais je m'appuie fortement sur le multithreading.

J'ai examiné quelques didacticiels sur les sockets PHP avec plusieurs clients. mais la plupart d'entre eux font des choses comme la création de nouveaux processus pour chaque client. Comme je vais avoir une boucle de jeu en permanence, je ne pense pas que cela convienne.

Ce que j'essaie de faire, c'est d'affecter des ports à chaque client au fur et à mesure de la connexion, d'écouter de nouveaux clients, d'échanger des données avec la liste actuelle des clients et d'exécuter la boucle de jeu tous ensemble.

Les endroits où j'ai besoin d'aide sont:

  • Comment trouver et attribuer des ports aux nouveaux clients, informer le client de ce port et le nettoyer lorsqu'ils se déconnectent.
  • Comment faire ci-dessus, et toutes les autres transactions de socket, sans bloquer la boucle de jeu. Il serait acceptable d'accepter des messages de clients en blocs partiels et d'agir uniquement sur un message complet.

Quelqu'un peut-il me donner des conseils techniques sur la façon d'atteindre ces objectifs? Je ne pense pas que tout cela ressemble trop à demander à PHP, mais corrigez-moi si je me trompe!

Un pseudo-code de ce que j'aimerais idéalement atteindre côté serveur. Aucune des fonctions ne doit bloquer:     Les clients du tableau;

while(gamerunning)
{
    CheckForNewClients();
    GetStatusFromClients();
    DoGameUpdate();
    SendGameStateToClients();
}

[Mettre à jour] Pour toute personne intéressée, j'ai créé une application dédiée prenant en charge les sockets Web (en utilisant spécifiquement Java et la bibliothèque de socket Web de TooTallNates) plutôt qu’un service Web réel. sockets dans le bac en raison de problèmes de sécurité.


10
2017-11-23 23:31


origine


Réponses:


Je ne suggère pas d'utiliser PHP pour ce type d'application. PHP ne supporte pas officiellement le multithreading et l'exécution d'un script PHP pour une période indéfinie (comme un serveur) n'est pas vraiment une fonctionnalité annoncée.

Bien sûr, vous pouvez essayer de faire l'histoire :)

(corrigez moi si je me trompe)


5
2017-11-23 23:35



Vous devez vraiment exécuter un démon PHP pour pouvoir le faire efficacement (et il faut que PHP 5.3). J'ai écrit un aperçu assez complet de l'utilisation PHP pour les processus démons. Quoi que vous choisissiez, je vous suggère d'utiliser un système de boucle d'exécution basé sur des événements.

J'ai conçu une bibliothèque de base RunLoop appelée LooPHP ce qui pourrait probablement être utile, surtout si vous allez faire face à *_select. Je serais plus qu'heureux de répondre à vos questions à ce sujet.

MODIFIER:

Dans un système basé sur des événements, vous ne devez pas simplement while une liste de commandes, vous réagissez à un auditeur. Par exemple...

Au lieu de faire:

while( 1 ) {
    ... /* listen, react */
} /* repeat */

Les boucles d'exécution fonctionnent en enregistrant un écouteur (sockets et autres générateurs d'événements asynchrones)

class ReactClass { ... }

$loop = new LooPHP_EventLoop( new ReactClass );

//add one time event
$loop->addEvent( function() {
    print "This event was called 0.5 second after being added\n";
}, 0.5 /* in seconds */ );

//this creates a repeating event, this is called right away and repeats
$add_event = function() use ( $loop, &$add_event ) {
    print "This event is REPEATEDLY called 0.1 every second\n";
    $loop->addEvent( $add_event, 0.1 );
};
$add_event();

//start the loop processing, no events are processed until this is done
$loop->run(); //php doesn't leave this call until the daemon is done
exit(0); //cleanly exit

Le cas ci-dessus est un EventLoop 1 source très simple et une fonction d'ajout manuel de temps (ceux-ci peuvent être ajoutés même dans un appel à ReactClass).

Dans l'application que je travaille, je devais avoir les deux flux d'événements asynchrones dans le backend (via un socket) et avoir ensuite la possibilité d'appeler des fonctions à un décalage arbitraire par rapport à l'événement d'origine (pour les clients expirés, etc.).

Si vous souhaitez plus d’exemples, vous pouvez les trouver à github.

J'espère que vous trouvez ça utile.


7
2017-11-24 01:46