← Назад к вопросам

Как работает websocket?

1.0 Junior🔥 191 комментариев
#Работа с сетью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

WebSocket — двусторонняя коммуникация в реальном времени

Что такое WebSocket

WebSocket — это протокол, который обеспечивает полнодуплексную (двусторонню) коммуникацию между клиентом и сервером через одно TCP соединение. В отличие от HTTP, это постоянное соединение.

HTTP vs WebSocket

HTTP (Request-Response):

Клиент → [Запрос] → Сервер
Клиент ← [Ответ] ← Сервер
(соединение закрывается)

Для каждого запроса нужно открывать новое соединение.

WebSocket (Persistent Connection):

Клиент ↔ [Соединение] ↔ Сервер
(одно соединение, двусторонний трафик)

Одно соединение для множества сообщений.

Как работает WebSocket

1. Handshake (HTTP upgrade):

Клиент отправляет:
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

Сервер ответит:
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

2. Persistent Connection:

  • Соединение остаётся открыто
  • Низкий overhead (нет HTTP headers)

3. Bidirectional Communication:

Время →
Клиент: "Hello"
Сервер: "Hi there!"
Клиент: "How are you?"
Сервер: "Fine, thanks!"

Реализация в iOS (URLSessionWebSocketTask)

import Foundation

class WebSocketManager {
    var webSocket: URLSessionWebSocketTask?
    
    func connect(to url: URL) {
        let session = URLSession(configuration: .default)
        webSocket = session.webSocketTask(with: url)
        webSocket?.resume()
        
        receiveMessage()
    }
    
    private func receiveMessage() {
        webSocket?.receive { [weak self] result in
            switch result {
            case .success(let message):
                switch message {
                case .string(let text):
                    print("Received: \(text)")
                case .data(let data):
                    print("Received data: \(data)")
                @unknown default:
                    break
                }
                // Ждём следующего сообщения
                self?.receiveMessage()
                
            case .failure(let error):
                print("WebSocket error: \(error)")
            }
        }
    }
    
    func send(_ message: String) {
        let message = URLSessionWebSocketTask.Message.string(message)
        webSocket?.send(message) { error in
            if let error = error {
                print("Send error: \(error)")
            }
        }
    }
    
    func disconnect() {
        webSocket?.cancel(with: .goingAway, reason: nil)
    }
}

Использование

let manager = WebSocketManager()
let url = URL(string: "wss://echo.websocket.org")!  // wss = WebSocket Secure

manager.connect(to: url)

// Отправить сообщение
manager.send("Hello, Server!")

// Закрыть соединение
manager.disconnect()

Типы сообщений

// String (текст)
let stringMessage = URLSessionWebSocketTask.Message.string("Hello")

// Data (бинарные данные)
let data = "Hello".data(using: .utf8)!
let dataMessage = URLSessionWebSocketTask.Message.data(data)

// Отправить
webSocket?.send(stringMessage) { error in
    // Handler
}

Ping-Pong (keep-alive)

func keepAlive() {
    webSocket?.sendPing { error in
        if let error = error {
            print("Ping error: \(error)")
        } else {
            print("Ping sent")
        }
    }
}

// Автоматический ping каждые 30 секунд
Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weak self] _ in
    self?.keepAlive()
}.fire()

Обработка состояний соединения

enum WebSocketState {
    case connecting
    case connected
    case disconnecting
    case disconnected(Error?)
}

class WebSocketManager: NSObject {
    @Published var state: WebSocketState = .disconnected(nil)
    
    func connect(to url: URL) {
        state = .connecting
        // ...
    }
    
    private func receiveMessage() {
        webSocket?.receive { [weak self] result in
            switch result {
            case .success:
                self?.state = .connected
                self?.receiveMessage()
            case .failure(let error):
                self?.state = .disconnected(error)
            }
        }
    }
}

Реальный пример: чат приложение

@MainActor
class ChatViewModel: ObservableObject {
    @Published var messages: [Message] = []
    @Published var connectionStatus: String = "Disconnected"
    
    private let webSocketManager = WebSocketManager()
    
    func connect() {
        let url = URL(string: "wss://chat-server.com/ws")!
        webSocketManager.connect(to: url)
        connectionStatus = "Connected"
    }
    
    func sendMessage(_ text: String) {
        webSocketManager.send(text)
        messages.append(Message(author: "Me", text: text))
    }
    
    func disconnect() {
        webSocketManager.disconnect()
        connectionStatus = "Disconnected"
    }
}

Когда использовать WebSocket

✅ Чат приложения (real-time messaging) ✅ Notifications (push updates) ✅ Multiplayer games ✅ Live trading/stocks ✅ Collaborative editing ✅ Live sports scores

❌ Не используй для обычного API (используй REST) ❌ Не используй для больших файлов (используй HTTP)

Преимущества

✅ Low latency (низкая задержка) ✅ Efficient (один TCP connection) ✅ Real-time (двусторонняя коммуникация) ✅ Lower server load

Недостатки

❌ Proxies не всегда поддерживают ❌ Сложнее масштабировать (sticky sessions) ❌ Требует постоянное соединение

Ключевые правила

✅ Используй URLSessionWebSocketTask (встроенный iOS 13+) ✅ Обрабатывай ошибки соединения ✅ Реализуй ping-pong для keep-alive ✅ Отправляй heartbeat периодически ✅ Переподключайся при разрыве ❌ Не отправляй большие сообщения ❌ Не забывай закрывать соединение

WebSocket — мощный инструмент для real-time коммуникации. Правильное использование обеспечивает отзывчивое и efficient приложение.

Как работает websocket? | PrepBro