Wie man ein Protokoll anpasst
Die Erstellung eines eigenen Protokolls ist eigentlich recht einfach. Ein einfaches Protokoll enthält im Allgemeinen zwei Teile:
- Ein Trennzeichen zur Unterscheidung der Daten
- Die Definition des Datenformats
Ein Beispiel
Protokolldefinition
Angenommen, das Trennzeichen zur Unterscheidung der Daten ist der Zeilenumbruch "\n" (es sei darauf hingewiesen, dass die Anfrage selbst keine Zeilenumbrüche enthalten sollte) und das Datenformat ist JSON. Hier ist ein Beispiel für ein Paket, das diese Regel erfüllt.
{"type":"message","content":"hello"}
Bitte beachten Sie das Zeilenumbruchszeichen am Ende des Anfragepakets (im PHP-Code wird dies als Doppelzitatszeichen-Zeichenfolge "\n" dargestellt), das das Ende einer Anfrage kennzeichnet.
Implementierungsschritte
Wenn Sie das oben genannte Protokoll in Workerman implementieren möchten, und angenommen, dass Ihr Protokoll JsonNL heißt und sich im Projekt MyApp befindet, müssen Sie die folgenden Schritte ausführen:
-
Platzieren Sie die Protokolldatei im Ordner Protokolle des Projekts, z.B. die Datei MyApp/Protocols/JsonNL.php
-
Implementieren Sie die Klasse JsonNL, wobei
namespace Protocols;
für den Namensraum verwendet wird. Es müssen drei statische Methoden implementiert werden: input, encode und decode.
Hinweis: Workerman wird diese drei statischen Methoden automatisch aufrufen, um die Paketierung, Entpackung und Verschlüsselung zu implementieren. Details zum Ablauf finden Sie in der nachstehenden Ablaufbeschreibung.
Interaktionsablauf zwischen Workerman und der Protokollklasse
- Angenommen, der Client sendet ein Datenpaket an den Server. Sobald der Server die Daten (möglicherweise teilweise) empfängt, ruft er sofort die Methode
input
des Protokolls auf, um die Länge des Pakets zu überprüfen. Die Methodeinput
gibt die Länge$length
an das Workerman-Framework zurück. - Nachdem das Workerman-Framework den Wert
$length
erhalten hat, überprüft es, ob im aktuellen Datenpuffer bereits eine Datenlänge von$length
empfangen wurde. Falls nicht, wird weiter auf Daten gewartet, bis die Datenpufferlänge nicht kleiner als$length
ist. - Wenn die Datenpufferlänge ausreicht, schneidet Workerman die Daten mit einer Länge von
$length
aus dem Puffer aus (d.h. Paketierung) und ruft die Methodedecode
des Protokolls zum Entpacken auf. Die entschlüsselten Daten werden in$data
zurückgegeben. - Nach dem Entpacken übergibt Workerman die Daten
$data
im Rahmen desonMessage($connection, $data)
-Callbacks an die Geschäftslogik. Innerhalb desonMessage
-Callbacks kann die Geschäftslogik die vollständigen und bereits entschlüsselten Daten des Clients mithilfe der Variablen$data
erhalten. - Wenn die Geschäftslogik in
onMessage
Daten an den Client senden muss, ruft Workerman automatisch die Methodeencode
des Protokolls auf, um das$buffer
zu verpacken, bevor es an den Client gesendet wird.
Spezifische Implementierung
Implementierung von MyApp/Protocols/JsonNL.php
namespace Protocols;
class JsonNL
{
/**
* Überprüft die Vollständigkeit des Pakets
* Gibt die Länge des Pakets im Puffer zurück, sofern sie ermittelt werden kann, andernfalls 0, um auf weitere Daten zu warten
* Bei einem Protokollfehler kann false zurückgegeben werden, was zur Trennung der aktuellen Client-Verbindung führt
* @param string $buffer
* @return int
*/
public static function input($buffer)
{
// Position des Zeilenumbruchs "\n" ermitteln
$pos = strpos($buffer, "\n");
// Wenn kein Zeilenumbruch vorhanden ist, kann die Paketlänge nicht bestimmt werden, daher 0 zurückgeben und auf weitere Daten warten
if($pos === false)
{
return 0;
}
// Wenn ein Zeilenumbruch vorhanden ist, die aktuelle Paketlänge (einschließlich des Zeilenumbruchs) zurückgeben
return $pos+1;
}
/**
* Verpackungsmethode, die automatisch aufgerufen wird, wenn Daten an den Client gesendet werden sollen
* @param string $buffer
* @return string
*/
public static function encode($buffer)
{
// JSON-Serialisierung, gefolgt von einem Zeilenumbruch als Abschlusskennung für die Anfrage
return json_encode($buffer)."\n";
}
/**
* Entpackungsmethode, die automatisch aufgerufen wird, wenn die empfangenen Daten die Länge des vom input zurückgegebenen Werts erreicht haben (Wert größer als 0)
* und gibt die vom onMessage-Callback erhaltenen Daten im $data-Parameter zurück
* @param string $buffer
* @return string
*/
public static function decode($buffer)
{
// Zeilenumbruch entfernen und in ein Array umwandeln
return json_decode(trim($buffer), true);
}
}
Damit ist das JsonNL-Protokoll implementiert und kann in der MyApp-Anwendung verwendet werden. Ein Beispiel zur Verwendung finden Sie unten.
Datei: MyApp\start.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$json_worker = new Worker('JsonNL://0.0.0.0:1234');
$json_worker->onMessage = function(TcpConnection $connection, $data) {
// $data enthält die vom Client übertragenen Daten, die bereits von JsonNL::decode verarbeitet wurden
echo $data;
// Die mit $connection->send gesendeten Daten werden automatisch mit der JsonNL::encode-Methode verpackt und an den Client gesendet
$connection->send(array('code'=>0, 'msg'=>'ok'));
};
Worker::runAll();
...
Hinweis
Workerman versucht, Protokolle im NamensraumProtocols
zu laden. Beispielsweise versuchtnew Worker('JsonNL://0.0.0.0:1234')
das ProtokollProtocols\JsonNL
zu laden.
Wenn der FehlerClass 'Protocols\JsonNL' not found
auftritt, lesen Sie bitte die Anleitung zur automatischen Ladung der Klassen.
Protokoll-Schnittstellenbeschreibung
Bei der Entwicklung von Protokollklassen in Workerman müssen drei statische Methoden implementiert werden: input, encode und decode. Die Schnittstellenbeschreibung für Protokolle finden Sie in Workerman/Protocols/ProtocolInterface.php und lautet wie folgt:
namespace Workerman\Protocols;
use \Workerman\Connection\ConnectionInterface;
/**
* Protokollschnittstelle
* @author walkor <walkor@workerman.net>
*/
interface ProtocolInterface
{
/**
* Zum Aufteilen des recv_buffer in Pakete
*
* Wenn die Länge des Anfragepakets aus $recv_buffer ermittelt werden kann, wird die Gesamtlänge zurückgegeben
* Andernfalls wird 0 zurückgegeben, was bedeutet, dass mehr Daten benötigt werden, um die Länge des aktuellen Anfragepakets zu bestimmen
* Wenn false oder eine negative Zahl zurückgegeben wird, wird dies als ungültige Anfrage betrachtet und die Verbindung wird getrennt
*
* @param ConnectionInterface $connection
* @param string $recv_buffer
* @return int|false
*/
public static function input($recv_buffer, ConnectionInterface $connection);
/**
* Zum Entpacken von Anfragen
*
* Wenn input einen Wert größer als 0 zurückgibt und Workerman genügend Daten empfangen hat, wird decode automatisch aufgerufen
* Anschließend wird das onMessage-Callback ausgelöst und die von decode entschlüsselten Daten als zweites Argument an das onMessage-Callback übergeben
* Mit anderen Worten, wenn eine vollständige Client-Anfrage empfangen wird, wird decode automatisch zur Entschlüsselung aufgerufen und muss nicht manuell im Geschäftscode aufgerufen werden
* @param ConnectionInterface $connection
* @param string $recv_buffer
*/
public static function decode($recv_buffer, ConnectionInterface $connection);
/**
* Zum Verpacken von Anfragen
*
* Wenn Daten an den Client gesendet werden sollen (z.B. mit $connection->send($data);), wird die encode-Methode automatisch verwendet, um die Daten in das entsprechende Protokollformat zu verpacken, bevor sie an den Client gesendet werden
* Mit anderen Worten, die an den Client gesendeten Daten werden automatisch durch encode verpackt und müssen nicht manuell im Geschäftscode aufgerufen werden
* @param ConnectionInterface $connection
* @param mixed $data
*/
public static function encode($data, ConnectionInterface $connection);
}
Hinweis:
Workerman schreibt nicht vor, dass Protokollklassen die ProtocolInterface implementieren müssen. In der Praxis genügt es, wenn die Klasse die drei statischen Methoden input, encode und decode enthält.