Cómo personalizar un protocolo
En realidad, personalizar un protocolo es algo bastante sencillo. Un protocolo simple generalmente consta de dos partes:
- Identificación de los límites de los datos
- Definición del formato de los datos
Un ejemplo
Definición del protocolo
Supongamos que el símbolo que identifica los límites de los datos es el salto de línea "\n" (es importante notar que los datos de la solicitud en sí no pueden contener el carácter de salto de línea). El formato de los datos es JSON. A continuación, se muestra un ejemplo de un paquete de solicitud que cumple con esta regla.
{"type":"message","content":"hello"}
Es importante observar que al final de los datos de la solicitud hay un carácter de salto de línea (representado por la cadena "\n" en PHP con comillas dobles), que indica el final de la solicitud.
Pasos de implementación
En Workerman, si deseas implementar el protocolo mencionado anteriormente (supongamos que se llama JsonNL) en un proyecto llamado MyApp, debes seguir los siguientes pasos:
-
Colocar el archivo del protocolo en la carpeta Protocols del proyecto, por ejemplo, el archivo sería MyApp/Protocols/JsonNL.php.
-
Implementar la clase JsonNL con el espacio de nombres
namespace Protocols;
, y asegurarse de implementar tres métodos estáticos: input, encode y decode.
Es importante destacar que Workerman llamará automáticamente a estos tres métodos estáticos para implementar la división, el empaquetado y el desempaquetado. Para obtener más detalles sobre el flujo de ejecución, consulta la explicación detallada a continuación.
Flujo de interacción entre Workerman y la clase de protocolo
- Supongamos que el cliente envía un paquete de datos al servidor. Cuando el servidor recibe los datos (puede ser parte de los datos), inmediatamente llama al método
input
del protocolo para verificar la longitud de este paquete. El métodoinput
devuelve el valor de longitud$length
a Workerman. - Una vez que Workerman recibe este valor de
$length
, comprueba si la longitud de los datos en el búfer actual es igual o mayor que$length
. Si no es así, continúa esperando datos hasta que la longitud del búfer sea igual o mayor que$length
. - Cuando la longitud del búfer es suficiente, Workerman corta los datos del búfer con una longitud de
$length
(es decir, divide el paquete) y llama al métododecode
del protocolo para desempaquetar los datos. El resultado del desempaquetado se almacena en la variable$data
. - Una vez desempaquetados, Workerman pasa los datos
$data
al negocio mediante la devolución de llamadaonMessage($connection, $data)
. El negocio puede utilizar la variable$data
para obtener los datos completos y desempaquetados enviados por el cliente. - Si el negocio necesita enviar datos al cliente mediante la llamada a
$connection->send($buffer)
, Workerman automáticamente utiliza el métodoencode
del protocolo para empaquetar$buffer
antes de enviarlo al cliente.
Implementación específica
Implementación de JsonNL en MyApp/Protocols/JsonNL.php
namespace Protocols;
class JsonNL
{
public static function input($buffer)
{
$pos = strpos($buffer, "\n");
if($pos === false)
{
return 0;
}
return $pos+1;
}
public static function encode($buffer)
{
return json_encode($buffer)."\n";
}
public static function decode($buffer)
{
return json_decode(trim($buffer), true);
}
}
Con esto, se completa la implementación del protocolo JsonNL, el cual puede ser utilizado en el proyecto MyApp como se muestra a continuación.
Archivo: 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 representa los datos enviados por el cliente, los cuales ya han sido procesados por JsonNL::decode
echo $data;
// Los datos de $connection->send se empaquetarán automáticamente mediante JsonNL::encode antes de ser enviados al cliente
$connection->send(array('code'=>0, 'msg'=>'ok'));
};
Worker::runAll();
Nota
Workerman intentará cargar el protocolo dentro del espacio de nombresProtocols
, por ejemplo, connew Worker('JsonNL://0.0.0.0:1234')
intentará cargar el protocoloProtocols\JsonNL
. Si se produce un error como "Clase 'Protocols\JsonNL' no encontrada", consulta la implementación de carga automática para hacerla automáticamente.
Explicación de la interfaz del protocolo
Para el desarrollo en Workerman, la clase del protocolo debe implementar tres métodos estáticos: input, encode y decode. Para obtener más detalles sobre la interfaz del protocolo, consulta Workerman/Protocols/ProtocolInterface.php, que se define de la siguiente manera:
namespace Workerman\Protocols;
use \Workerman\Connection\ConnectionInterface;
interface ProtocolInterface
{
public static function input($recv_buffer, ConnectionInterface $connection);
public static function decode($recv_buffer, ConnectionInterface $connection);
public static function encode($data, ConnectionInterface $connection);
}
Nota:
En Workerman, no es estrictamente necesario que la clase del protocolo implemente la interfaz ProtocolInterface. En realidad, solo se requiere que la clase del protocolo contenga los tres métodos estáticos: input, encode y decode.