WebSocket в Go
WebSocket даёт постоянное двустороннее соединение поверх HTTP upgrade. Подходит для чатов, live-дашбордов, игр и push-уведомлений, где REST с polling слишком медленный. Транспорт ниже HTTP — в TCP и UDP, основа HTTP — веб на stdlib.
См. также: WebSocket — обзор · Асинхронность.
WebSocket, HTTP и TCP
| Протокол | Модель | Типичное применение |
|---|---|---|
| REST/HTTP | Запрос → ответ | CRUD API |
| WebSocket | Долгое двустороннее | Чат, тикеры, совместное редактирование |
| Raw TCP | Произвольные байты | Свой бинарный протокол |
WebSocket начинается как обычный HTTP GET с заголовками Upgrade: websocket и Connection: Upgrade. После handshake соединение остаётся открытым — фреймы текста или бинарных данных идут в обе стороны.
Библиотека
Стандартная библиотека не содержит полноценного WebSocket-стека. На практике используют github.com/gorilla/websocket или nhooyr.io/websocket. Ниже — gorilla.
go get github.com/gorilla/websocket
Upgrader и сервер
Код ITЗагрузка примера кода…
Разбор:
Upgrader.Upgradeпереводит HTTP-соединение в WebSocket; до upgrade ответ уже нельзя писать через обычныйResponseWriter.CheckOriginзащищает от CSRF-подобных подключений с чужих сайтов — в dev часто ослабляют, в prod проверяютOrigin.ReadMessage/WriteMessageработают с целыми фреймами; для потоковой обработки —NextReader/NextWriter.- Цикл завершается при закрытии клиентом или сетевой ошибке;
defer conn.Close()освобождает ресурсы.
WebSocket в браузере идёт как wss:// поверх TLS. Сервер поднимают через ListenAndServeTLS или reverse proxy (nginx, Caddy), который проксирует Upgrade — пример nginx для WebSocket.
Hub — рассылка нескольким клиентам
Типичный паттерн hub: центральная горутина регистрирует клиентов и рассылает broadcast.
Код ITЗагрузка примера кода…
Разбор:
- Одна goroutine-hub сериализует доступ к
clients— без mutex. register/unregisterвызывают из HTTP-handler послеUpgrade.- При ошибке записи клиент удаляют из map, иначе hub "залипнет" на мёртвом соединении.
- Broadcast через канал отделяет producers (HTTP, другие goroutine) от рассылки.
Связь с select и каналами: hub — классический event loop на select.
Клиент (Go)
conn, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if err := conn.WriteMessage(websocket.TextMessage, []byte("hello")); err != nil {
log.Fatal(err)
}
_, msg, err := conn.ReadMessage()
Разбор:
DefaultDialer.Dialвыполняет client-side handshake.- Таймауты и TLS настраивают через поля
Dialer(HandshakeTimeout,TLSClientConfig). - Для нагрузочных клиентов переиспользуют одно соединение, а не Dial на каждое сообщение.
Ping, pong и дедлайны
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
})
Разбор:
- Без read deadline "тихие" клиенты держат goroutine и file descriptor.
- Ping/pong (RFC 6455) обнаруживает обрыв; gorilla может слать ping из фоновой goroutine.
- Паттерн совпадает с
SetDeadlineна TCP — см. TCP и UDP в Go.
WebSocket и горутины
На каждое соединение обычно одна goroutine на чтение и одна на запись (или hub). Ограничивайте число клиентов семафором — как для TCP-серверов.
При shutdown сервиса закрывают listener, затем все websocket.Conn, чтобы goroutine завершились до exit.
Ключевые тезисы
- WebSocket — upgrade HTTP, дальше фреймы, а не новый TCP-port.
CheckOrigin, TLS и лимиты соединений обязательны в production.- Hub на каналах масштабирует broadcast без гонок на map клиентов.
Мини-практикум
- Echo-сервер
/wsи клиент изwebsocket.DefaultDialer. - Добавьте hub с broadcast "новое сообщение всем".
- Сравните задержку push через WebSocket и polling REST раз в секунду.
Типичные ошибки
| Ошибка | Последствие |
|---|---|
CheckOrigin: true в prod | Подключение с чужого сайта |
Писать в ResponseWriter после Upgrade | Сломанный протокол |
| Нет ping/deadline | Утечка goroutine |
Concurrent WriteMessage без mutex | Race, corrupted frames |
Связанные материалы
- TCP и UDP в Go — UNIX domain sockets, сырой транспорт
- Веб на stdlib — HTTP до upgrade
- Gin — REST рядом с WebSocket на том же порту через
http.Server
Обзор WebSocket в сетевом разделе — WebSocket.