Maison  >  Article  >  cadre php  >  Partagez le protocole personnalisé de Workerman pour résoudre le problème délicat et de déballage

Partagez le protocole personnalisé de Workerman pour résoudre le problème délicat et de déballage

青灯夜游
青灯夜游avant
2022-12-12 20:09:511793parcourir

workermanComment le protocole personnalisé résout-il les problèmes délicats et de déballage ? L'article suivant vous présentera comment le protocole personnalisé de Workerman résout le problème des paquets persistants et du déballage. J'espère qu'il sera utile à tout le monde.

Partagez le protocole personnalisé de Workerman pour résoudre le problème délicat et de déballage

Avant-propos :

Depuis que j'ai récemment utilisé Workerman pour implémenter le côté serveur des jeux en ligne Unity3D, bien que la communication directe puisse également être réalisée via le protocole TCP, quelques problèmes mineurs ont été découverts lors des tests proprement dits. [Recommandation associée : « workerman Tutorial »]

Par exemple, les paquets de données des deux côtés sont-ils sous forme de chaînes ? De plus, comme ce sont des chaînes, ils doivent être coupés, et parfois ils apparaîtront lorsque le client ? ou le serveur les reçoit. Signaler une erreur. Après avoir imprimé les journaux, il a été constaté que les paquets reçus aux deux extrémités étaient dans un format qui n'avait pas été convenu à l'avance. Il s'agit du phénomène de collage et de déballage TCP. La solution à ce problème est très simple, et il y en a beaucoup sur Internet, mais ici, je souhaite utiliser le protocole que j'ai implémenté pour le résoudre, et je le laisserai pour plus tard.

Question et réponse :

J'ai lu quelques conventions sur Internet concernant le format des paquets de données de communication des jeux en ligne. Si vous n'utilisez pas un langage faiblement typé pour créer des scripts côté serveur, d'autres utilisent souvent des tableaux d'octets. Mais lorsque PHP reçoit le tableau d'octets, il s'agit en fait d'une chaîne, mais le principe est que le tableau d'octets n'a pas de conversion spécifique. Prenons C# comme exemple. Lors de la résolution de problèmes tels que les paquets persistants, la longueur d'octet (BitConverter.GetBytes (len)) sera ajoutée avant le tableau d'octets. Mais lorsque celui-ci est transmis au serveur PHP pour réception, les 4 premiers octets de la chaîne ne peuvent pas être affichés, et même après de nombreuses méthodes de conversion, ils ne peuvent pas être récupérés. Plus tard, j'ai aussi pensé à utiliser la méthode de données Protobuf. Bien que PHP puisse convertir des données, j'ai abandonné car je ne connaissais pas le client C#.

Un autre problème est qu'en fait, la plupart de la synchronisation de trames utilisée par d'autres serveurs de jeux en ligne utilise le protocole UDP, qui est également partagé par TCP et UDP. Mais s’il ne s’agit que d’un petit jeu multijoueur en ligne, il est tout à fait possible d’utiliser PHP comme serveur et protocole de communication TCP. Revenons ensuite au protocole personnalisé de Workerman et aux problèmes délicats et de déballage.

Protocole personnalisé :

Workerman a encapsulé plusieurs fonctions socket de PHP (en ce qui concerne la fonction socket, si vous êtes prêt à jouer avec, PHP peut également écrire un gadget de transfert de fichiers), qui est également intégré basé sur TCP Il dispose de plusieurs protocoles de couche application, tels que Http, Websocket, Frame, etc. Il réserve également l'intersection aux utilisateurs pour définir leurs propres protocoles. Il leur suffit d'implémenter son interface ProtocolInterface. Ce qui suit est une brève introduction à plusieurs méthodes qui doivent être implémentées pour les interfaces suivantes.

1. Méthode de saisie

Dans cette méthode, le paquet de données peut être décompressé, vérifié, filtré, etc. avant d'être reçu par le serveur. Renvoyer 0 signifie placer le paquet de données dans le tampon de l'extrémité réceptrice et continuer à attendre. Renvoyer la longueur spécifiée signifie retirer la longueur du tampon. S'il y a une exception, vous pouvez également renvoyer false pour fermer directement la connexion client.

2. méthode d'encodage

Cette méthode est le traitement par le serveur du format du paquet de données avant d'envoyer le paquet de données au client, c'est-à-dire l'encapsulation du paquet. Cela doit être convenu par le front-end et le back-end. .

3. méthode de décodage

Cette méthode est également le déballage, qui consiste à prendre la longueur spécifiée du tampon jusqu'à l'endroit où onMessage doit être traité avant la réception, comme le déploiement logique, etc.

Phénomènes provoqués par le déballage des paquets collants :

Puisque TCP est basé sur des flux, et parce qu'il s'agit de la couche de transport, lorsque l'application de la couche supérieure communique via des sockets (entendus comme des interfaces), elle ne connaît pas les données transmises over Où commence et se termine le package. Envoyez simplement la colle ou dégroupez selon l'ensemble d'algorithmes de congestion de TCP. Littéralement, les paquets collants sont plusieurs paquets de données envoyés ensemble. À l'origine, il y avait deux paquets, mais le client n'en a reçu qu'un. Le déballage consiste à diviser un paquet de données en plusieurs paquets. Il aurait dû recevoir un paquet de données, mais un seul a été reçu. Par conséquent, si le problème n'est pas résolu, comme mentionné précédemment et que la chaîne est transmise conformément à l'accord, une erreur peut être signalée lors du déballage.

Solution à un débit de paquet collant:

1. au fractionnement des chaînes, car il y a toujours un problème avec les 4 octets plus la longueur du paquet sur la première page ci-dessus. Autrement dit, la première fois que le paquet est envoyé sans la longueur du paquet, les simulations ultérieures de collage ou de décompression resteront dans le tampon. Vous pouvez vous référer au code ci-dessus pour la démonstration suivante.

1. Démarrage du service et connexion client

2. 服务业务端代码

        数据包格式说明一下,字符串以逗号分割,数据包以 #分割,逗号分割第一组是业务方法,如 Login 表示登陆传递,Pos 表示坐标传递,后面带的就是对应方法需要的参数了。

<?php

use Workerman\Worker;

require_once __DIR__ . &#39;/vendor/autoload.php&#39;;

// #### create socket and listen 1234 port ####
$worker = new Worker(&#39;tank://0.0.0.0:1234&#39;);

// 4 processes
//$worker->count = 4;

$worker->onWorkerStart = function ($connection) {
    echo "游戏协议服务启动……";
};

// Emitted when new connection come
$worker->onConnect = function ($connection) {
    echo "New Connection\n";
    $connection->send("address: " . $connection->getRemoteIp() . " " . $connection->getRemotePort());
};

// Emitted when data received
$worker->onMessage = function ($connection, $data) use ($worker, $stream) {

    echo "接收的数据:" . $data . "\n";

    // 简单实现接口分发
    $arr = explode(",", $data);

    if (!is_array($arr) || !count($arr)) {
        $connection->close("数据格式错误", true);
    }

    $func = strtoupper($arr[0]);
    $client = $connection->getRemoteAddress();

    switch($func) {
        case "LOGIN":
            $sendData = "Login1";
            break;
        case "POS":
            $positionX = $arr[1] ?? 0;
            $positionY = $arr[2] ?? 0;
            $positionZ = $arr[3] ?? 0;

            $sendData = "POS,$client,$positionX,$positionY,$positionZ";
            break;
    }

    $connection->send($sendData);
};

// Emitted when connection is closed
$worker->onClose = function ($connection) {
    echo "Connection closed\n";
};


// 接收缓冲区溢出回调
$worker->onBufferFull = function ($connection) {
    echo "清理缓冲区吧";
};

Worker::runAll();

?>

3. 粘包测试

    只需要在客户端模拟两个数据包连在一起,但是要以 #分隔,看看服务端接收的时候是一几个包进行处理的。

4. 拆包测试

        拆包模拟只需要将一个数据包分成两次发送,看看服务端接收的时候能不能显示或者说能不能按约定好的格式正确显示。

更多编程相关知识,请访问:编程教学!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer