Следите за новинками
в нашем Telegram канале. Жми, чтобы подписаться:)
⊗goSpWsBc 266 of 280 menu
◀ ▶

Рассылка по WebSocket в Go

Когда несколько клиентов уже записаны в общую карту, сервер может разослать одну и ту же фразу каждому активному каналу. Обход делают под тем же замком, что и при добавлении, чтобы карта не менялась посередине цикла.

На каждом элементе вызывают отправку текстового кадра с общим срезом байтов. Ошибку записи в один канал обычно логируют и продолжают обход: остальные клиенты все равно должны получить сообщение.

Хранилище с методом рассылки и сервер, который после перевода кладет клиента в карту:

package main import ( "log" "net/http" "sync" "github.com/gorilla/websocket" ) type hub struct { mu sync.Mutex conns map[*websocket.Conn]struct{} } func (h *hub) add(conn *websocket.Conn) { h.mu.Lock() h.conns[conn] = struct{}{} h.mu.Unlock() } func (h *hub) broadcast(text []byte) { h.mu.Lock() defer h.mu.Unlock() for conn := range h.conns { err := conn.WriteMessage(websocket.TextMessage, text) if err != nil { log.Println(err) } } } func main() { h := &hub{conns: make(map[*websocket.Conn]struct{})} upgrader := websocket.Upgrader{} http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } h.add(conn) go func(c *websocket.Conn) { defer c.Close() _, _, err := c.ReadMessage() if err != nil { return } }(conn) }) go func() { h.broadcast([]byte("news: server up")) }() log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil)) }

В учебном файле рассылку запускают отдельной горутиной; в реальной программе ее вызывают, когда пришло событие или прочитали сообщение от одного клиента.

Тот же обход карты без HTTP-регистрации, если карта уже заполнена:

package main import ( "log" "sync" "github.com/gorilla/websocket" ) func broadcastAll(mu *sync.Mutex, conns map[*websocket.Conn]struct{}, text []byte) { mu.Lock() defer mu.Unlock() for conn := range conns { err := conn.WriteMessage(websocket.TextMessage, text) if err != nil { log.Println(err) } } } func main() { var mu sync.Mutex conns := make(map[*websocket.Conn]struct{}) broadcastAll(&mu, conns, []byte("hello all")) }

Дано сообщение:

text := []byte("alert: done")

Напишите функцию, которая под замком обходит карту conns и отправляет text каждому каналу как текстовый кадр.

Дан фрагмент рассылки:

for conn := range h.conns { conn.WriteMessage(websocket.TextMessage, text) }

Скажите, какую гонку дает такой обход без замка, если другая горутина в это время удаляет клиента из карты.

Скажите, почему при ошибке отправки одному клиенту цикл обычно не прерывают сразу для всех остальных.

← →
↑
Мы используем cookie для работы сайта, аналитики и персонализации. Обработка данных происходит согласно Политике конфиденциальности.
принять все настроить отклонить