Что такое Websocket?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Что такое WebSocket
Определение
WebSocket — это протокол полнодуплексной коммуникации, который работает поверх TCP и позволяет двусторонний обмен данными в реальном времени между клиентом и сервером без необходимости в polling или long-polling.
Проблема, которую решает WebSocket
HTTP — однонаправленный запрос-ответ
Проблемы HTTP:
- Для получения обновлений нужно постоянно отправлять запросы (polling)
- Много сетевого трафика на пустые ответы
- Высокая задержка в доставке данных от сервера к клиенту
WebSocket — двусторонний постоянный канал
WebSocket решает эти проблемы через постоянное двустороннее соединение.
Как работает WebSocket
Фаза 1: Upgrade (handshake)
Клиент отправляет обычный HTTP запрос с просьбой upgrade на WebSocket:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Сервер соглашается:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
После upgrade TCP соединение остаётся открытым, но теперь используется WebSocket протокол вместо HTTP.
Фаза 2: Двусторонний обмен (frames)
Данные передаются фреймами. Каждый фрейм содержит:
- FIN — последний ли это фрейм
- Opcode — тип данных (текст, бинарный, контроль)
- Mask — маска для безопасности (клиент всегда маскирует)
- Payload — данные
Фаза 3: Закрытие соединения
Любая сторона может инициировать закрытие, отправив Close фрейм.
Практический пример на Java
Использование Spring WebSocket
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class ChatWebSocketHandler extends TextWebSocketHandler {
private List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
System.out.println("Client connected: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws IOException {
String payload = message.getPayload();
System.out.println("Received: " + payload);
// Broadcast сообщение всем клиентам
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
s.sendMessage(new TextMessage(
"User " + session.getId() + ": " + payload
));
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
System.out.println("Client disconnected: " + session.getId());
}
}
Конфигурация
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatWebSocketHandler(), "/ws/chat")
.setAllowedOrigins("*");
}
}
Клиентская часть (JavaScript)
const ws = new WebSocket("ws://localhost:8080/ws/chat");
ws.onopen = (event) => {
console.log("Connected");
ws.send("Hello from client!");
};
ws.onmessage = (event) => {
console.log("Message: " + event.data);
};
ws.onclose = (event) => {
console.log("Disconnected");
};
Использование Java WebSocket API
Server Endpoint
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
@ServerEndpoint("/ws/notification")
public class NotificationEndpoint {
private static Set<Session> clients = Collections.synchronizedSet(new HashSet<>());
@OnOpen
public void onOpen(Session session) {
clients.add(session);
System.out.println("New connection: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
System.out.println("Message from " + session.getId() + ": " + message);
// Отправить всем клиентам
for (Session client : clients) {
if (client.isOpen()) {
client.getBasicRemote().sendText(message);
}
}
}
@OnClose
public void onClose(Session session) {
clients.remove(session);
System.out.println("Connection closed: " + session.getId());
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
}
WebSocket vs HTTP
| Аспект | HTTP | WebSocket |
|---|---|---|
| Направление | Однонаправленный | Двусторонний |
| Инициация | Только клиент | Обе стороны |
| Задержка | Высокая | Низкая |
| Трафик | Много заголовков | Минимум |
| Масштабируемость | Хорошая | Требует памяти |
| Кеширование | Встроенное | Нет |
Когда использовать WebSocket
Используй WebSocket для:
- Чат приложений
- Real-time уведомлений
- Live трансляции данных
- Совместного редактирования
- Online игр
- IoT датчиков
Не используй WebSocket для:
- Простых REST API запросов
- Статического контента
- Когда нужна история запросов и кеширование
Best Practices
-
Обрабатывай разъединения: Клиент должен иметь логику переподключения при потере соединения
-
Используй heartbeat для проверки соединения: Сервер отправляет ping каждые 30 секунд
-
Масштабирование на несколько серверов:
- Используй Redis Pub/Sub для broadcast между серверами
- Или используй Message Broker (RabbitMQ, Kafka)
-
Безопасность:
- Всегда используй WSS (WebSocket Secure, поверх TLS)
- Валидируй сообщения
- Аутентифицируй при подключении
Вывод
WebSocket — это мощный протокол для real-time коммуникации, который кардинально отличается от HTTP своей двусторонней природой. Он идеален для приложений, требующих мгновенного обмена данными между сервером и клиентом.