Bonjour,

J'ai commencé à apprendre le PHP depuis déjà et depuis, étant de nature très curieuse, souvent quand j'arrive sur un site, je me pose la question de savoir comment je pourrais reproduire certaines des fonctionnalités qui s'y trouvent.
En général, j'y arrive en cherchant sur Google ou par moi-même.

Aujourd'hui, en cherchant un serveur mineraft sympa, je suis tombé sur ce site : https://www.serveurs-minecraft.com/
Ce site qui répertorie des serveurs minercaft avec quelques informations.
Il propose également de trier les serveurs selon différents critères et notamment par le nombre de joueurs connectés.

C'est sur cette fonctionnalité que je coince.
En ce qui concerne l'obtention du nombre de joueurs en ligne , en cherchant un peu sur Google, j'ai appris qu'il était possible de l'obtenir grâce à la fonction fsockopen().
Pour ce qui est du tri la seule solution que j'ai trouvé serait de sélectionner tous les éléments de la table qui contiendrait les informations concernant les serveur (dont l'ip) , et pour chaque serveur, d'utiliser fosockopen() pour obtenir le nombre de joueurs connectés et en suite faire le tri. Mais en terme de performance, je ne pense pas que cette méthode soit très efficace.

Je me demande donc s'il est possible de le faire en php/Mysql. Et si oui, comment ?

Merci d'avance

7 réponses


StarTechs
Réponse acceptée

Alors tout d'abord il faut regarder comment récupérer les utilisateurs connectés. Pour cela tu fais une liste en base de données des serveurs minecraft ainsi que le port utilisés par ces serveurs. Tu peux en effet récupérer le nombre d'utilisateurs connectés mais la procédure pour cela est un peu plus complexe. Les jeux vidéos ne sont pas des sites web, aussi le protocole utilisé est le TCP par envoi de websockets (qui permettent d'échanger des informations de manière très rapide entre le client et un serveur) sur le port par défaut de minecraft à savoir le 25565.

Une fois que tu sais cela, tu peux écrire ton script PHP qui doit successivement :

  • Ouuvrir une connexion via des websockets sur le protocole TCP sur une adresse données sur le port 25565 (par défaut).
  • Lire les informations de ce serveur.
  • Parser ces informations pour en extraire le nombres de joueurs connectés.

Pour cela j'utilise la fonction php stream_socket_client. J'ai du faire quelques recherches et tests pour connaitre le port utilisés et les informations que l'on récupère. La lecture des sockets est un peu fastidieuse mais la voici :

<?php
<?php
    $date = time();

    // J'ouvre une connexion via le protocole TCP sur l'adresse d'un serveur MC sur le protocole 25565
    // En l'occurence le serveur MC est http://nerd.nu/
    if($socket = @stream_socket_client("s.nerd.nu:25565", $errno, $errstr, 1))
    {
        // On est connecté au serveur, on récupère les infos récupérées
        fwrite($socket, "\xfe"); // écriture dans un fichier
        $head = fread($socket, 2048); // On lit les les 2048 premiers octets du fichiers (les seuls qui nous intéressent)
        $head = str_replace("\x00", '', $head); // Parsage du fichier + on le rend lisible
        $head = substr($head, 2); // On retire des caractères inutiles

        // On récupère enfin les informations dans un tableau PHP
        $datas = explode("\xa7", $head);

        // On ferme le fichier et le socket qu'on a ouvert
        unset($head);
        fclose();

        // Il se peut qu'il y ai des erreurs lors de la lecture des informations vu qu'elles sont asynchrones
        // Par exemple le serveur qui down pendant le téléchargement des informations (ou autre)

        // On récupère :
        $title = $datas[0]; // Une chaine qui correspond je crois au nom du serveur (ou au mode peut être);
        $online_players = $datas[1]; // Le nomrbe de joueurs connectés actuellement
        $max_players = $datas[2]; // Le nombre de joueurs max autorisés

        $curDate = time();
        $count = $curDate - $date;

        echo '<h1>Informations récupérées en : '. $count . 'ms </h1>';
        echo '<ul>';
            echo '<li>' . $title . '</li>';
            echo '<li>' . $online_players . '</li>';
            echo '<li>' . $max_players . '</li>';
        echo '</ul>';
    }
    else
        die('Le serveur ne répond pas'); // Si le serveur ne répond pas (erreur d'hôte, de port, serveur down, ...)

Petit mot sur mes fwrite et fread, on utilise habituellement un fichier que l'on a au préalablement ouvert avec fopen, néanmoins c'est une étape qui est déjà faite quand on utilise les sockets (c'est un flux qui nous est retourné).

Voiàl pour le script de base. Ensuite imagine un fichier PHP qui va récupérer une liste de serveurs depuis une base de données et qui boucle dessus. Ensuite tu ajoutes un cron job (une tâche effectuée par linux tout les X temps) et qui va éxecuter ce script, couple ça à un cache PHP dans le site et ça te donne comment le site serveurs-minecraft est développé. Comme tu le vois la lecture de ces informations est très rapide ! (le script s'execute en 2ms chez moi). Même avec 500 serveurs, ça ne mettra qu'une seconde à récupérer toutes les informations. Rajoute la partie récupération des serveurs en bdd + leur update, tu ne dois pas dépasser les 3s d'execution.

Rien de bien compliqué au final. En tout cas c'est une question très loin d'être bête je me suis bien amusé à te répondre. Les deux seuls élements un peu tricky étaient savoir que c'était en TCP sur le port 25565 par défaut que j'ai trouvé sur un wiki minecraft. Le ddeuxième élement était la lecture du fichier de sockets, pour cela j'ai enregistré les informations dans un fichier juste à coté de mon script (que j'ouvre en php via fopen) et avec un convertisseur hexadecimal j'ai trouvé mes informations en tatonnant un petit peu.

un grand merci à toi earhater. :)
grace à toi je comprend mieux comment ça fonctionne.

petites erreurs dans le code:
-au moment de fermer le fichier tu a oublié l'argument. C'est donc fclose($socket); au lieu de fclose();
-pour le temps d’exécution, il n'est pas millisecondes mais en seconde. Pour qu'il soit en millisecondes :
$date = microtime();
$curDate = microtime();
$count = ($curDate - $date)/1000;

Y a-t-il une différence entre la fonction fsockopen() et stream_socket_client() ?

@falcon - La prochaine fois pose ta question dans un autre post. Personne n'y répondra vu que le sujet est résolu.

Sinon tu peux t'aider de la doc de PHP

Plus précisément ici.

Très exact usernameless, c'est vrai que je t'ai répondu à deux heures du matin j'avais pas les yeux en face des trous. Par contre ça change absolument tout sur mon estimation de temps que je t'ai donné xD

earhater pourrais tu détailler une peu plus la deuxième partie? Là ou tu parle de la façon de faire le tri.
j'ai pas très bien compris et je touve cette partie très intéressante.

@falcon : oui une différence fondamentale même. Fsockopen va envoyer ou recevoir un socket de manière synchrone. stream_socket_client va recevoir un flux d'informations qui seront écrites en mémoire, ou dans l'exemple dans un fichier, au fur et à mesure de leur réception.

@plus : je proposais juste l'idée d'écrire le script dans un fichier séparé de notre site et de l'appeler tous les X temps pour mettre à jour la base de données du site. ça évitera de faire cette opération en interne.