Трансляция сообщений
Отправляйте сообщения множеству клиентов
«Трансляция сообщений» — бесплатный урок Go Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Go Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Go Academy содержит 4 уроков всего.
Отправка многим клиентам
Чатам и потокам данных в реальном времени нужно отправлять одно сообщение всем подключённым клиентам. Поскольку каждый WebSocket допускает только одного писателя, нужен шаблон координации: центральный узел.
Шаблон центрального узла
Центральный узел — это центральная горутина, которая владеет множеством клиентов и каналом рассылки. Клиенты регистрируются и удаляются, а узел рассылает сообщения всем клиентам. Ни одна общая структура отображения не изменяется напрямую несколькими горутинами.
Структуры данных центрального узла
Центральный узел содержит:
- Множество клиентов (
map[*Client]bool) - Канал сообщений
broadcast - Каналы
registerиunregister
type Hub struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unregister chan *Client
}Цикл работы центрального узла
Одна горутина Run выбирает данные из каналов. Поскольку отображение изменяет только эта горутина, мьютекс не нужен.
func (h *Hub) Run() {
for {
select {
case c := <-h.register:
h.clients[c] = true
case c := <-h.unregister:
delete(h.clients, c)
close(c.send)
case msg := <-h.broadcast:
for c := range h.clients {
c.send <- msg
}
}
}
}Канал отправки для каждого клиента
У каждого клиента есть буферизованный канал send chan []byte. Центральный узел записывает в него данные, а отдельная горутина записи выбирает их и отправляет в сокет. Это соблюдает правило одного писателя.
type Client struct {
conn *websocket.Conn
send chan []byte
}Горутина записи
Для каждого клиента запускается writePump, которая получает данные из send и записывает их в сокет. Если канал закрывается, она отправляет кадр закрытия.
func (c *Client) writePump() {
for msg := range c.send {
c.conn.WriteMessage(websocket.TextMessage, msg)
}
}Как избежать медленных клиентов
Если один клиент работает медленно, его буферизованный канал send заполняется. Распространённая политика: если буфер заполнен, отключить клиента, а не блокировать весь центральный узел.
select {
case c.send <- msg:
default:
close(c.send)
delete(h.clients, c)
}Почему каналы лучше мьютексов
Девиз Go: «обменивайтесь данными, чтобы совместно использовать память». Направление всех изменений через каналы в одну горутину позволяет избежать состояний гонки при работе с отображением клиентов без явной блокировки.
Рассылка сообщения
Любой обработчик может выполнить рассылку, отправив сообщение в канал центрального узла; центральный узел разошлёт его всем зарегистрированным клиентам.
hub.broadcast <- []byte("server announcement")Адресная отправка и рассылка
Для комнат или личных сообщений храните клиентов с ключом в виде комнаты или пользовательского ID и перебирайте только соответствующее подмножество, а не всех клиентов. Благодаря этому чат с большим количеством комнат остаётся эффективным.
Исполняемый пример: рассылка с помощью каналов
Эта автономная программа моделирует рассылку центральным узлом одного сообщения в несколько каналов клиентов, используя только стандартную библиотеку и горутины.
package main
import (
"fmt"
"sync"
)
func main() {
clients := []chan string{make(chan string, 1), make(chan string, 1), make(chan string, 1)}
msg := "hello all"
for _, c := range clients {
c <- msg // fan-out
}
var wg sync.WaitGroup
for i, c := range clients {
wg.Add(1)
go func(id int, ch chan string) {
defer wg.Done()
fmt.Printf("client %d got: %s\n", id, <-ch)
}(i, c)
}
wg.Wait()
}Проверка
Проверьте своё понимание рассылки.
Повторение
Вы научились отправлять сообщения многим клиентам:
- Горутина центрального узла владеет множеством клиентов и каналом рассылки
- У каждого клиента есть буферизованный канал отправки, из которого данные выбирает горутина записи
- Это соблюдает правило одного писателя для каждого соединения
- Отключайте медленных клиентов, чтобы центральный узел оставался отзывчивым
Часто задаваемые вопросы
Урок «Трансляция сообщений» бесплатный?
Да — полный текст урока «Трансляция сообщений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Go Academy, подпишись на CoddyKit PRO. Курс Go Academy содержит 4 уроков всего.
Чему я научусь в уроке «Трансляция сообщений»?
Отправляйте сообщения множеству клиентов Ты практикуешь Go Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Go Academy?
Предыдущий опыт не требуется. Go Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Трансляция сообщений»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Go Academy?
Да. Каждый урок Go Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы WebSocket
- Использование gorilla/websocket
- Трансляция сообщений
- Управление соединениями