Explorando WebSocket

Home PDF

Esta entrada del blog fue organizada con la asistencia de ChatGPT-4o.


Introducción

Hola a todos, soy Li Zhiwei. Como fundador y CTO de la plataforma CodeReview, y ex ingeniero de LeanCloud, tengo una amplia experiencia en WebSocket, especialmente en el desarrollo de SDKs de mensajería instantánea (IM).

La importancia de WebSocket

WebSocket es un protocolo que proporciona un canal de comunicación full-duplex sobre una única conexión TCP. Se utiliza ampliamente en aplicaciones modernas que requieren interacción en tiempo real, como mensajería instantánea, comentarios en tiempo real, juegos multijugador, edición colaborativa y precios de acciones en tiempo real.

Aplicaciones Modernas de WebSocket

WebSocket se utiliza ampliamente en las siguientes áreas:

La evolución de WebSocket

Sondeo (Polling): El cliente solicita frecuentemente actualizaciones al servidor. Sondeo largo (Long Polling): El servidor mantiene la solicitud abierta hasta que hay nueva información disponible. Conexión bidireccional HTTP: Requiere múltiples conexiones para enviar y recibir, y cada solicitud incluye cabeceras HTTP. Conexión única TCP (WebSocket): Supera las limitaciones de la conexión bidireccional HTTP, ofreciendo mayor capacidad en tiempo real y menor latencia.

Implementación de WebSocket en iOS

WebSocket es un protocolo de comunicación que permite una conexión bidireccional entre un cliente y un servidor. En iOS, puedes utilizar la clase URLSessionWebSocketTask para implementar WebSocket en tu aplicación. A continuación, te guiaré a través de los pasos básicos para configurar y utilizar WebSocket en una aplicación iOS.

1. Crear una instancia de URLSessionWebSocketTask

Primero, necesitas crear una instancia de URLSessionWebSocketTask utilizando una URL de WebSocket. Aquí tienes un ejemplo de cómo hacerlo:

import Foundation

let url = URL(string: "wss://your.websocket.server")!
let webSocketTask = URLSession.shared.webSocketTask(with: url)

2. Conectar al servidor WebSocket

Una vez que hayas creado la instancia de URLSessionWebSocketTask, puedes conectarte al servidor WebSocket utilizando el método resume():

webSocketTask.resume()

3. Enviar mensajes al servidor

Para enviar un mensaje al servidor, puedes utilizar el método send(_:) de URLSessionWebSocketTask. Aquí tienes un ejemplo de cómo enviar un mensaje de texto:

let message = URLSessionWebSocketTask.Message.string("Hello, WebSocket!")
webSocketTask.send(message) { error in
    if let error = error {
        print("Error sending message: \(error)")
    }
}

4. Recibir mensajes del servidor

Para recibir mensajes del servidor, puedes utilizar el método receive(completionHandler:). Este método te permite recibir mensajes de forma asíncrona:

webSocketTask.receive { result in
    switch result {
    case .failure(let error):
        print("Error receiving message: \(error)")
    case .success(let message):
        switch message {
        case .string(let text):
            print("Received text: \(text)")
        case .data(let data):
            print("Received data: \(data)")
        @unknown default:
            print("Received unknown message type")
        }
    }
}

5. Cerrar la conexión WebSocket

Cuando ya no necesites la conexión WebSocket, puedes cerrarla utilizando el método cancel(with:reason:):

webSocketTask.cancel(with: .goingAway, reason: nil)

6. Manejar errores y reconexiones

Es importante manejar los errores y las reconexiones en tu aplicación. Puedes utilizar el método URLSessionDelegate para manejar eventos de conexión y desconexión.

class WebSocketManager: NSObject, URLSessionWebSocketDelegate {
    var webSocketTask: URLSessionWebSocketTask?

    func connect() {
        let url = URL(string: "wss://your.websocket.server")!
        let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
        webSocketTask = session.webSocketTask(with: url)
        webSocketTask?.resume()
    }

    func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
        print("WebSocket connected")
    }

    func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
        print("WebSocket disconnected")
    }
}

Conclusión

Implementar WebSocket en iOS es relativamente sencillo utilizando las APIs proporcionadas por URLSession. Con esta guía, deberías poder configurar una conexión WebSocket, enviar y recibir mensajes, y manejar errores y reconexiones en tu aplicación iOS. ¡Buena suerte con tu implementación!

Bibliotecas populares de WebSocket para iOS:

Usando SRWebSocket

  1. Inicialización y conexión:
    SRWebSocket *webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://echo.websocket.org"]]];
    webSocket.delegate = self;
    [webSocket open];
    
  2. Enviar mensaje:
    [webSocket send:@"Hello, World!"];
    
  3. Recibir mensajes: Implementa los métodos de SRWebSocketDelegate para manejar los mensajes entrantes y eventos.

  4. Manejo de errores y notificaciones de eventos: Maneja adecuadamente los errores y notifica a los usuarios sobre problemas de conexión.

Explicación detallada del protocolo WebSocket

WebSocket opera sobre TCP e introduce varias mejoras:

El núcleo del protocolo WebSocket

El protocolo WebSocket es un protocolo de comunicación bidireccional que permite la transmisión de datos en tiempo real entre un cliente y un servidor. A diferencia de HTTP, que es un protocolo de solicitud-respuesta, WebSocket mantiene una conexión persistente entre el cliente y el servidor, lo que permite la transmisión de datos en ambos sentidos sin necesidad de realizar múltiples solicitudes.

Características clave de WebSocket:

  1. Conexión persistente: Una vez establecida la conexión WebSocket, esta permanece abierta, lo que permite la transmisión de datos en tiempo real sin la sobrecarga de establecer y cerrar conexiones repetidamente.

  2. Bidireccional: Tanto el cliente como el servidor pueden enviar datos en cualquier momento, lo que facilita la comunicación en tiempo real.

  3. Baja latencia: Debido a la naturaleza persistente de la conexión, la latencia en la transmisión de datos es significativamente menor en comparación con HTTP.

  4. Soporte para datos binarios y de texto: WebSocket puede transmitir tanto datos binarios como de texto, lo que lo hace versátil para una variedad de aplicaciones.

Establecimiento de la conexión WebSocket

El proceso de establecimiento de una conexión WebSocket comienza con un “handshake” HTTP. El cliente envía una solicitud HTTP al servidor con un encabezado especial Upgrade: websocket, indicando que desea cambiar al protocolo WebSocket. Si el servidor acepta la solicitud, responde con un código de estado 101 Switching Protocols, y la conexión se actualiza a WebSocket.

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

El servidor responde con:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Una vez completado el handshake, la conexión se convierte en una conexión WebSocket y puede comenzar la transmisión de datos.

Transmisión de datos

Los datos en WebSocket se transmiten en forma de “frames”. Un frame puede contener datos de texto o binarios, y puede ser enviado en cualquier dirección. Los frames están diseñados para ser eficientes y tienen un encabezado pequeño que incluye información como el tipo de frame y la longitud de los datos.

// Ejemplo de envío de datos desde el cliente
const socket = new WebSocket('ws://example.com/chat');

socket.onopen = function(event) {
    socket.send('Hola, servidor!');
};

socket.onmessage = function(event) {
    console.log('Mensaje recibido del servidor: ' + event.data);
};

Cierre de la conexión

La conexión WebSocket puede cerrarse en cualquier momento por cualquiera de las partes (cliente o servidor). El cierre se realiza enviando un frame de cierre, que puede incluir un código de estado y un mensaje opcional que indica la razón del cierre.

// Ejemplo de cierre de conexión desde el cliente
socket.close(1000, 'Cierre normal');

Conclusión

El protocolo WebSocket es una herramienta poderosa para aplicaciones que requieren comunicación en tiempo real, como chats en línea, juegos multijugador y actualizaciones en vivo. Su capacidad para mantener una conexión persistente y bidireccional lo hace ideal para escenarios donde la latencia y la eficiencia son críticas.

1. Apretón de manos (Handshake): El apretón de manos de WebSocket utiliza el mecanismo de actualización de HTTP:

2. Transferencia de datos: Los frames de WebSocket pueden contener texto en UTF-8, datos binarios y frames de control, como cierre, ping y pong.

3. Seguridad: El navegador agrega automáticamente la cabecera Origin, la cual no puede ser falsificada por otros clientes.

URI de WebSocket

Protocolo de tramas WebSocket

Estructura del Frame:

Clave de máscara: Se utiliza para prevenir ataques de intermediario al enmascarar los fotogramas del cliente.

Cierre del apretón de manos (Handshake)

Marco de cierre:

Ejemplo

Ejemplo 1: Mensaje de texto sin enmascarar en un solo frame

0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f

Contiene “Hello”

Ejemplo 2: Mensaje de texto enmascarado en un solo marco

0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58

Contiene “Hello”, con clave de enmascaramiento.

Ejemplo 3: Mensaje de texto fragmentado sin enmascarar

0x01 0x03 0x48 0x65 0x6c
0x80 0x02 0x6c 0x6f

El mensaje fragmentado contiene dos tramas: “Hel” y “lo”.

Temas avanzados

Enmascaramiento y Desenmascaramiento:

Fragmentación:

Marcos de Control:

Escalabilidad

Los datos de extensión pueden colocarse antes de los datos de la aplicación en el cuerpo del mensaje:

Envío:

Cierre del apretón de manos (Handshake):

Cerrar la conexión:

Referencias

Agradecimientos

Gracias a todos por su atención. Si tienen más preguntas o desean discutir algún tema, no duden en contactarme en GitHub o Weibo.


Back 2025.01.18 Donate