Sobes.tech
Middle

¿Qué solución utilizaste para trabajar con WebSocket?

sobes.tech AI

Respuesta de la IA

En proyectos que requerían interacción bidireccional en tiempo real, utilicé con éxito URLSessionWebSocketTask.

Esta es una solución integrada del framework Network, disponible desde iOS 13.

Ventajas de URLSessionWebSocketTask:

  • Nativo: Integrado con URLSession, lo que simplifica la gestión de conexiones y el manejo de eventos de red.
  • Rendimiento: Optimizado para trabajar con la red a nivel del sistema.
  • Fiabilidad: Mecanismo incorporado de pings y pongs, intentos automáticos de reconexión (aunque puede requerir lógica adicional para escenarios complejos).
  • Seguridad: Soporta TLS de serie.

Etapas principales de trabajo:

  1. Crear una instancia de URLSessionWebSocketTask.

    // Crear una instancia de URLSession con configuración predeterminada
    let session = URLSession(configuration: .default)
    // Inicializar la tarea WebSocket
    let webSocketTask = session.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    
  2. Iniciar la conexión.

    // Reanudar la tarea para establecer la conexión
    webSocketTask.resume()
    
  3. Enviar mensajes (texto o datos binarios).

    // Enviar un mensaje de texto
    webSocketTask.send(.string("Hello, world!")) { error in
        if let error = error {
            print("Error al enviar: \(error)")
        }
    }
    
    // Enviar datos binarios
    let dataToSend = Data([1, 2, 3])
    webSocketTask.send(.data(dataToSend)) { error in
        if let error = error {
            print("Error al enviar: \(error)")
        }
    }
    
  4. Recepción de mensajes. Es un proceso asíncrono.

    // Función recursiva para recibir mensajes
    func receiveMessage() {
        webSocketTask.receive { result in
            switch result {
            case .failure(let error):
                print("Error al recibir: \(error)")
                // Manejar error, posiblemente reintentar conexión
            case .success(let message):
                switch message {
                case .string(let text):
                    print("Mensaje de texto recibido: \(text)")
                case .data(let data):
                    print("Datos binarios recibidos: \(data)")
                @unknown default:
                    fatalError("Tipo de mensaje desconocido")
                }
                // Continuar escuchando mensajes
                self.receiveMessage()
            }
        }
    }
    
    // Iniciar escucha
    receiveMessage()
    
  5. Manejar eventos del ciclo de vida de la conexión (apertura, cierre, errores) usando el delegado URLSessionWebSocketDelegate.

    // Ejemplo de implementación del delegado
    class WebSocketHandler: NSObject, URLSessionWebSocketDelegate {
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
            print("Conexión abierta")
            // Iniciar recepción de mensajes tras apertura
            receiveMessage() // Se asume que receiveMessage está definido
        }
    
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
            let reasonString = reason.flatMap { String(data: $0, encoding: .utf8) } ?? "Razón desconocida"
            print("Conexión cerrada con código \(closeCode.rawValue), razón: \(reasonString)")
            // Lógica de reconexión o cierre
        }
    
        // Manejar errores de la sesión
        func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            if let error = error {
                print("Tarea finalizada con error: \(error)")
                // Lógica adicional de manejo de errores
            }
        }
    }
    
    // Al crear la sesión, usar el delegado
    let delegate = WebSocketHandler()
    let sessionWithDelegate = URLSession(configuration: .default, delegate: delegate, delegateQueue: OperationQueue())
    let webSocketTaskWithDelegate = sessionWithDelegate.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    

También he utilizado bibliotecas de terceros, como Starscream, cuando se requería soporte para versiones más antiguas de iOS o funcionalidades específicas no disponibles en la solución nativa (por ejemplo, reconexión automática con retroceso exponencial). Sin embargo, cuando era posible, prefería URLSessionWebSocketTask por las ventajas mencionadas anteriormente.