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:
-
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")!) -
Rozpoczęcie połączenia.
// Wznowienie zadania w celu ustanowienia połączenia webSocketTask.resume() -
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)") } } -
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() -
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.