Sobes.tech
Middle

Jakie rozwiązanie użyłeś do pracy z WebSocket?

sobes.tech AI

Odpowiedź od AI

W projektach, w których wymagana była dwukierunkowa interakcja w czasie rzeczywistym, z powodzeniem używałem URLSessionWebSocketTask.

Jest to wbudowane rozwiązanie frameworka Network, dostępne od iOS 13.

Zalety URLSessionWebSocketTask:

  • Nativeness: Zintegrowane z URLSession, co upraszcza zarządzanie połączeniami i obsługę zdarzeń sieciowych.
  • Wydajność: Optymalizowane do pracy z siecią na poziomie systemu.
  • Niezawodność: Wbudowany mechanizm pingów i pongów, automatyczne próby ponownego łączenia (chociaż może wymagać dodatkowej logiki dla scenariuszy złożonych).
  • Bezpieczeństwo: Obsługuje TLS od razu.

Główne etapy pracy:

  1. Tworzenie instancji URLSessionWebSocketTask.

    // Tworzenie instancji URLSession z domyślną konfiguracją
    let session = URLSession(configuration: .default)
    // Inicjalizacja zadania WebSocket
    let webSocketTask = session.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    
  2. Rozpoczęcie połączenia.

    // Wznowienie zadania w celu ustanowienia połączenia
    webSocketTask.resume()
    
  3. Wysyłanie wiadomości (tekstowych lub binarnych danych).

    // Wysyłanie wiadomości tekstowej
    webSocketTask.send(.string("Hello, world!")) { error in
        if let error = error {
            print("Błąd podczas wysyłania: \(error)")
        }
    }
    
    // Wysyłanie danych binarnych
    let dataToSend = Data([1, 2, 3])
    webSocketTask.send(.data(dataToSend)) { error in
        if let error = error {
            print("Błąd podczas wysyłania: \(error)")
        }
    }
    
  4. Odbieranie wiadomości. To proces asynchroniczny.

    // Funkcja rekurencyjna do odbierania wiadomości
    func receiveMessage() {
        webSocketTask.receive { result in
            switch result {
            case .failure(let error):
                print("Błąd podczas odbioru: \(error)")
                // Obsługa błędów, ewentualnie ponowne połączenie
            case .success(let message):
                switch message {
                case .string(let text):
                    print("Odebrano wiadomość tekstową: \(text)")
                case .data(let data):
                    print("Odebrane dane binarne: \(data)")
                @unknown default:
                    fatalError("Nieznany typ wiadomości")
                }
                // Kontynuuj słuchanie wiadomości
                self.receiveMessage()
            }
        }
    }
    
    // Rozpocznij słuchanie
    receiveMessage()
    
  5. Zarządzanie zdarzeniami cyklu życia połączenia (otwarcie, zamknięcie, błędy) za pomocą delegata URLSessionWebSocketDelegate.

    // Przykład implementacji delegata
    class WebSocketHandler: NSObject, URLSessionWebSocketDelegate {
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
            print("Połączenie otwarte")
            // Rozpocznij odbieranie wiadomości po otwarciu
            receiveMessage() // Zakłada się, że receiveMessage jest zdefiniowana
        }
    
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
            let reasonString = reason.flatMap { String(data: $0, encoding: .utf8) } ?? "Nieznany powód"
            print("Połączenie zamknięte z kodem \(closeCode.rawValue), powód: \(reasonString)")
            // Logika ponownego połączenia lub zakończenia
        }
    
        // Obsługa błędów sesji
        func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            if let error = error {
                print("Zadanie zakończone z błędem: \(error)")
                // Dodatkowa logika obsługi błędów
            }
        }
    }
    
    // Podczas tworzenia sesji użyj delegata
    let delegate = WebSocketHandler()
    let sessionWithDelegate = URLSession(configuration: .default, delegate: delegate, delegateQueue: OperationQueue())
    let webSocketTaskWithDelegate = sessionWithDelegate.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    

Używałem również bibliotek stron trzecich, takich jak Starscream, gdy wymagana była obsługa starszych wersji iOS lub funkcji niedostępnych w rozwiązaniu natywnym (np. automatyczne ponowne łączenie z wykładniczym opóźnieniem). Jednak, gdy to było możliwe, preferowałem URLSessionWebSocketTask ze względu na wyżej wymienione zalety.