Fundamentos teóricos del protocolo WebSockets

El protocolo WebSocket se basa en las conexiones de red TCP/IP, que se caracterizan por una dirección IP (o un nombre de dominio que la sustituya) y un número de puerto. El protocolo HTTP/HTTPS, con el que ya hemos practicado en el capítulo sobre funciones de red, se basa en el mismo principio. Allí, los números de puerto estándar eran 80 (para conexiones inseguras) y 443 (para conexiones seguras). No existe un número de puerto específico para WebSocket, por lo que los proveedores de servicios web pueden elegir cualquier número disponible. Todos nuestros ejemplos utilizarán el puerto 9000.

Al especificar URL como prefijos de protocolo WebSocket, utilizamos ws (para conexiones no seguras) y wss (para conexiones seguras).

El formato WebSocket es más eficiente en términos de transferencia de datos que HTTP, ya que utiliza muchos menos datos de control.

El establecimiento de la conexión inicial para un servicio WebSocket repite completamente una solicitud de página web HTTP/HTTPS: es necesario enviar una solicitud GET con encabezados especialmente preparados. Una característica de estos encabezados es la presencia de las líneas

Connection: Upgrade
Upgrade: websocket

así como algunas líneas adicionales que informan de la versión del protocolo WebSocket y cadenas especiales generadas aleatoriamente. Las claves que intervienen en el procedimiento de «handshaking» entre el cliente y el servidor.

Sec-WebSocket-Key: ...
Sec-WebSocket-Version: 13

En la práctica, este «handshake» implica que el servidor comprueba la disponibilidad de las opciones solicitadas por el cliente y, en respuesta, con encabezados HTTP estándar, confirma el cambio al modo WebSocket o lo rechaza. La razón más simple para el rechazo puede ser si usted está tratando de conectarse a través de WebSockets a un servidor web simple donde el servidor WebSocket no se proporciona o la versión requerida no es compatible.

La versión actual del protocolo WebSockets se conoce con el nombre simbólico Hybi y el número 13. Una versión anterior y más sencilla llamada Hixie puede ser útil para la compatibilidad con versiones anteriores. En lo que sigue, utilizaremos solo Hybi, aunque también se incluye una implementación de Hixie.

Una conexión correcta se indica mediante los siguientes encabezados HTTP en la respuesta del servidor:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ...

El servidor calcula y rellena el campo Sec-WebSocket-Accept basándose en la Sec-WebSocket-Key para confirmar el cumplimiento del protocolo. Todo ello está regulado por la especificación RFC6455 y se admitirá también en nuestros programas MQL.

Para mayor claridad, el procedimiento se muestra en la siguiente imagen:

Interacción entre cliente y servidor a través del protocolo WebSocket

Interacción entre cliente y servidor a través del protocolo WebSocket

Tras establecer una conexión WebSocket, el cliente y el servidor pueden intercambiar información empaquetada en bloques especiales: frames y mensajes. Un mensaje puede constar de uno o varios frames. El tamaño del frame, según la especificación, está limitado a un número astronómico de 263 bytes (9223372036854775807 ~ 9.22 exabytes), pero las implementaciones específicas pueden, por supuesto, tener límites más mundanos, ya que este límite teórico no parece práctico para enviar en un paquete.

En cualquier momento, el cliente o el servidor pueden poner fin a la conexión, previa «despedida cortés» (véase más adelante) o simplemente cerrando el socket de red.

Los frames pueden ser de distintos tipos según se especifique en su encabezado (de 4 a 16 bytes de longitud) que viene al principio de cada frame. Como referencia, vamos a enumerar los códigos operativos (están presentes en el primer byte del encabezado) y la finalidad de los frames de distintos tipos.

  • 0 - frame de continuación (hereda las propiedades del frame anterior);
  • 1 - frame con información de texto;
  • 2 - frame con información binaria;
  • 8 - solicitud de frame para cerrar y confirmación de cierre de la conexión (enviada para una «despedida cortés»);
  • 9 - frame de ping; puede ser enviado periódicamente por cualquiera de los dos lados para asegurarse de que la conexión está físicamente guardada;
  • 10 - frame de pong, enviado en respuesta a un frame de ping.

El último frame de un mensaje se marca con un bit especial en el encabezado. Por supuesto, cuando un mensaje consta de un solo frame, también es el último. La longitud de la carga útil también se indica en el encabezado.