Ответ
Да, я реализовывал WebSocket-взаимодействие в Go. Чаще всего для этого используется библиотека gorilla/websocket
, так как она предоставляет больше гибкости и функциональности по сравнению со стандартной golang.org/x/net/websocket
.
Процесс реализации выглядит так:
- HTTP Upgrader: WebSocket-соединение начинается как обычный HTTP-запрос, который затем "обновляется" до протокола WebSocket. Для этого используется
websocket.Upgrader
. - Цикл чтения и записи: После успешного обновления соединения, сервер входит в бесконечный цикл, где он слушает входящие сообщения от клиента (
conn.ReadMessage()
) и обрабатывает их. Запись клиенту (conn.WriteMessage()
) обычно происходит в отдельной горутине для неблокирующей работы.
Ключевые аспекты, которые нужно учитывать:
- Конкурентность: Объект соединения
*websocket.Conn
не является потокобезопасным для одновременной записи. Запись должна производиться только из одной горутины. Чтение безопасно производить из другой горутины. - Управление соединениями: Необходимо создать пул или менеджер соединений для отслеживания всех активных клиентов, например, для рассылки сообщений всем участникам чата.
- Обработка ошибок и закрытия: Важно корректно обрабатывать ошибки, возникающие при чтении или записи, и закрывать соединение.
gorilla/websocket
позволяет установитьCloseHandler
для выполнения логики при закрытии соединения клиентом. - Ping/Pong: Для поддержания соединения активным и обнаружения "мертвых" клиентов используется механизм
Ping/Pong
. Библиотека может делать это автоматически, если настроитьPingHandler
.
Пример простого обработчика:
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true }, // В проде нужна более строгая проверка
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
for {
// Читаем сообщение от клиента
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println("read error:", err)
break
}
// Отправляем сообщение обратно клиенту (эхо)
if err := conn.WriteMessage(messageType, p); err != nil {
log.Println("write error:", err)
break
}
}
}
WebSocket отлично подходит для создания интерактивных приложений: чатов, систем уведомлений в реальном времени, онлайн-игр и дашбордов.