Sobes.tech
Middle

Какво решение използвахте за работа с WebSocket?

sobes.tech AI

Отговор от AI

В проекти, където беше необходима двупосочна комуникация в реално време, успешно използвах URLSessionWebSocketTask.

Това е вградено решение на framework-а Network, налично от iOS 13.

Предимствата на URLSessionWebSocketTask:

  • Нативно: Интегрирано с URLSession, което улеснява управлението на връзките и обработката на мрежовите събития.
  • Производителност: Оптимизирано за работа с мрежата на системно ниво.
  • Надеждност: Вградени механизми за ping и pong, автоматични опити за повторно свързване (въпреки че може да е необходима допълнителна логика за сложни сценарии).
  • Сигурност: Поддържа TLS директно от кутията.

Основни стъпки:

  1. Създаване на инстанция на URLSessionWebSocketTask.

    // Създаване на инстанция на URLSession с настройки по подразбиране
    let session = URLSession(configuration: .default)
    // Инициализация на WebSocket задачата
    let webSocketTask = session.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    
  2. Стартиране на връзката.

    // Възобновяване на задачата за установяване на връзката
    webSocketTask.resume()
    
  3. Изпращане на съобщения (текст или двоични данни).

    // Изпращане на текстово съобщение
    webSocketTask.send(.string("Hello, world!")) { error in
        if let error = error {
            print("Грешка при изпращане: \(error)")
        }
    }
    
    // Изпращане на двоични данни
    let dataToSend = Data([1, 2, 3])
    webSocketTask.send(.data(dataToSend)) { error in
        if let error = error {
            print("Грешка при изпращане: \(error)")
        }
    }
    
  4. Получаване на съобщения. Това е асинхронен процес.

    // Рекурсивна функция за получаване на съобщения
    func receiveMessage() {
        webSocketTask.receive { result in
            switch result {
            case .failure(let error):
                print("Грешка при получаване: \(error)")
                // Обработка на грешката, възможно опит за повторно свързване
            case .success(let message):
                switch message {
                case .string(let text):
                    print("Получено текстово съобщение: \(text)")
                case .data(let data):
                    print("Получени двоични данни: \(data)")
                @unknown default:
                    fatalError("Непознат тип съобщение")
                }
                // Продължаваме да слушаме съобщения
                self.receiveMessage()
            }
        }
    }
    
    // Стартиране на слушателя
    receiveMessage()
    
  5. Обработка на събития от жизнения цикъл на връзката (отваряне, затваряне, грешки) с използване на делегата URLSessionWebSocketDelegate.

    // Пример за реализация на делегат
    class WebSocketHandler: NSObject, URLSessionWebSocketDelegate {
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
            print("Връзката е отворена")
            // Започваме да слушаме съобщения след отваряне
            receiveMessage() // Предполага се, че receiveMessage е дефинирана
        }
    
        func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
            let reasonString = reason.flatMap { String(data: $0, encoding: .utf8) } ?? "Неизвестна причина"
            print("Връзката е затворена с код \(closeCode.rawValue), причина: \(reasonString)")
            // Логика за повторно свързване или приключване
        }
    
        // Обработка на грешки на сесията
        func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            if let error = error {
                print("Задачата е приключила с грешка: \(error)")
                // Допълнителна логика за обработка на грешки
            }
        }
    }
    
    // При създаване на сесията използвайте делегата
    let delegate = WebSocketHandler()
    let sessionWithDelegate = URLSession(configuration: .default, delegate: delegate, delegateQueue: OperationQueue())
    let webSocketTaskWithDelegate = sessionWithDelegate.webSocketTask(with: URL(string: "wss://example.com/socket")!)
    

Също така съм използвал външни библиотеки като Starscream, когато е било необходимо да се поддържат по-стари версии на iOS или определени функционалности, които не са налични в нативното решение (например автоматично повторно свързване с експоненциално забавяне). Въпреки това, ако е възможно, предпочитах URLSessionWebSocketTask поради гореспоменатите предимства.