Beispiele
Beispiel Eins
Protokolldefinition
- Die ersten 10 Byte sind festgelegt, um die Gesamtlänge des Datenpakets zu speichern. Wenn die Stellen nicht ausreichen, werden sie mit 0 aufgefüllt.
- Datenformat ist XML
Beispieldatenpaket
0000000121<?xml version="1.0" encoding="ISO-8859-1"?>
<request>
<module>user</module>
<action>getInfo</action>
</request>
Hier steht 0000000121 für die Gesamtlänge des Datenpakets, gefolgt vom Inhalt des Datenkörpers im XML-Format.
Protokollimplementierung
namespace Protocols;
class XmlProtocol
{
public static function input($recv_buffer)
{
if(strlen($recv_buffer) < 10)
{
// Weniger als 10 Bytes, Rückgabe 0, um auf weitere Daten zu warten
return 0;
}
$total_len = base_convert(substr($recv_buffer, 0, 10), 10, 10);
return $total_len;
}
public static function decode($recv_buffer)
{
$body = substr($recv_buffer, 10);
return simplexml_load_string($body);
}
public static function encode($xml_string)
{
$total_length = strlen($xml_string) + 10;
$total_length_str = str_pad($total_length, 10, '0', STR_PAD_LEFT);
return $total_length_str . $xml_string;
}
}
Beispiel Zwei
Protokolldefinition
- Die ersten 4 Bytes sind als Netzwerk-Byte-Reihenfolge für eine nicht-negative ganze Zahl definiert und kennzeichnen die Gesamtlänge des Pakets.
- Der Datenbereich ist ein JSON-String.
Beispieldatenpaket
****{"type":"message","content":"hello all"}
Hier repräsentieren die ersten vier Sternchen vier Bytes in Netzwerk-Byte-Reihenfolge für die Gesamtlänge des Datenpakets, gefolgt vom Datenkörper im JSON-Format.
Protokollimplementierung
namespace Protocols;
class JsonInt
{
public static function input($recv_buffer)
{
if(strlen($recv_buffer)<4)
{
return 0;
}
$unpack_data = unpack('Ntotal_length', $recv_buffer);
return $unpack_data['total_length'];
}
public static function decode($recv_buffer)
{
$body_json_str = substr($recv_buffer, 4);
return json_decode($body_json_str, true);
}
public static function encode($data)
{
$body_json_str = json_encode($data);
$total_length = 4 + strlen($body_json_str);
return pack('N',$total_length) . $body_json_str;
}
}
Beispiel Drei (Dateiübertragung mit binärem Protokoll)
Protokolldefinition
struct
{
unsigned int total_len; // Gesamtlänge des Pakets, in Big-Endian-Netzwerkbyte-Reihenfolge
char name_len; // Länge des Dateinamens
char name[name_len]; // Dateiname
char file[total_len - BinaryTransfer::PACKAGE_HEAD_LEN - name_len]; // Dateidaten
}
Beispiel für das Protokoll
*****logo.png******************
Hier repräsentiert das erste Sternchen vier Zeichen in Big-Endian-Netzwerkbyte-Reihenfolge für die Gesamtlänge des Datenpakets, gefolgt von einem einzelnen Zeichen zur Speicherung der Dateinamenlänge, gefolgt vom Dateinamen und den Rohdaten der Binärdatei.
Protokollimplementierung
namespace Protocols;
class BinaryTransfer
{
const PACKAGE_HEAD_LEN = 5;
public static function input($recv_buffer)
{
if(strlen($recv_buffer) < self::PACKAGE_HEAD_LEN)
{
return 0;
}
$package_data = unpack('Ntotal_len/Cname_len', $recv_buffer);
return $package_data['total_len'];
}
public static function decode($recv_buffer)
{
$package_data = unpack('Ntotal_len/Cname_len', $recv_buffer);
$name_len = $package_data['name_len'];
$file_name = substr($recv_buffer, self::PACKAGE_HEAD_LEN, $name_len);
$file_data = substr($recv_buffer, self::PACKAGE_HEAD_LEN + $name_len);
return array(
'file_name' => $file_name,
'file_data' => $file_data,
);
}
public static function encode($data)
{
return $data;
}
}
Beispiel für die Verwendung des Serverprotokolls
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('BinaryTransfer://0.0.0.0:8333');
$worker->onMessage = function(TcpConnection $connection, $data)
{
$save_path = '/tmp/'.$data['file_name'];
file_put_contents($save_path, $data['file_data']);
$connection->send("Upload erfolgreich. Speicherpfad $save_path");
};
Worker::runAll();
Beispiel für den Client "client.php" (Verwendung von PHP, um Datei zu übertragen)
<?php
/** Dateiübertragungsclient **/
$address = "127.0.0.1:8333";
if(!isset($argv[1]))
{
exit("Verwendung: php client.php \$file_path\n");
}
$file_to_transfer = trim($argv[1]);
if(!is_file($file_to_transfer))
{
exit("$file_to_transfer existiert nicht\n");
}
$client = stream_socket_client($address, $errno, $errmsg);
if(!$client)
{
exit("$errmsg\n");
}
stream_set_blocking($client, 1);
$file_name = basename($file_to_transfer);
$name_len = strlen($file_name);
$file_data = file_get_contents($file_to_transfer);
$PACKAGE_HEAD_LEN = 5;
$package = pack('NC', $PACKAGE_HEAD_LEN + strlen($file_name) + strlen($file_data), $name_len) . $file_name . $file_data;
fwrite($client, $package);
echo fread($client, 8192),"\n";
Beispiel für die Client-Verwendung
Führen Sie den folgenden Befehl in der Befehlszeile aus: php client.php <Dateipfad>
Zum Beispiel: php client.php abc.jpg
Beispiel vier (Verwendung des Textprotokolls zum Hochladen von Dateien)
Protokolldefinition
Json mit Zeilenumbruch. Das Json enthält den Dateinamen und die base64_encodierte (das Volumen wird um 1/3 vergrößert) Dateidaten.
Protokollbeispiel
{"file_name":"logo.png","file_data":"PD9waHAKLyo......"}\n
Beachten Sie, am Ende steht ein Zeilenumbruchzeichen. In PHP wird dies durch das Doppelanführungszeichen "\n"
dargestellt.
Protokollumsetzung
namespace Protocols;
class TextTransfer
{
public static function input($recv_buffer)
{
$recv_len = strlen($recv_buffer);
if($recv_buffer[$recv_len-1] !== "\n")
{
return 0;
}
return strlen($recv_buffer);
}
public static function decode($recv_buffer)
{
// Entpacken
$package_data = json_decode(trim($recv_buffer), true);
// Dateinamen abrufen
$file_name = $package_data['file_name'];
// base64_encodierte Dateidaten abrufen
$file_data = $package_data['file_data'];
// base64_decode zur Wiederherstellung der ursprünglichen Binärdateidaten
$file_data = base64_decode($file_data);
// Daten zurückgeben
return array(
'file_name' => $file_name,
'file_data' => $file_data,
);
}
public static function encode($data)
{
// Hier können die an den Client gesendeten Daten je nach Bedarf codiert werden. Hier werden sie einfach als Text zurückgegeben.
return $data;
}
}
Beispiel für die Verwendung des Serverprotokolls
Hinweis: Die Schreibweise ist die gleiche wie beim binären Upload, sodass fast keine Änderungen am Geschäftscode erforderlich sind, um das Protokoll zu wechseln.
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker('TextTransfer://0.0.0.0:8333');
// Datei in tmp speichern
$worker->onMessage = function(TcpConnection $connection, $data)
{
$save_path = '/tmp/'.$data['file_name'];
file_put_contents($save_path, $data['file_data']);
$connection->send("Upload erfolgreich. Speicherort $save_path");
};
Worker::runAll();
Clientdatei textclient.php (hier wird der Client-Upload in PHP simuliert)
<?php
/** Datei-Upload-Client **/
// Upload-Adresse
$address = "127.0.0.1:8333";
// Überprüfen der Dateipfadparameter
if(!isset($argv[1]))
{
exit("Verwenden Sie php client.php \$file_path\n");
}
// Dateipfad für den Upload
$file_to_transfer = trim($argv[1]);
// Die zu übertragende Datei existiert lokal nicht
if(!is_file($file_to_transfer))
{
exit("$file_to_transfer nicht vorhanden\n");
}
// Socket-Verbindung herstellen
$client = stream_socket_client($address, $errno, $errmsg);
if(!$client)
{
exit("$errmsg\n");
}
stream_set_blocking($client, 1);
// Dateiname
$file_name = basename($file_to_transfer);
// Dateibinärdaten
$file_data = file_get_contents($file_to_transfer);
// Base64-Codierung
$file_data = base64_encode($file_data);
// Datenpaket
$package_data = array(
'file_name' => $file_name,
'file_data' => $file_data,
);
// Protokollpaket Json + Zeilenumbruch
$package = json_encode($package_data)."\n";
// Upload ausführen
fwrite($client, $package);
// Ergebnis ausgeben
echo fread($client, 8192),"\n";
Beispiel für die Verwendung des Clients
Führen Sie den Befehl php textclient.php <Dateipfad>
in der Befehlszeile aus.
Beispiel: php textclient.php abc.jpg