0Pricing
Go Academy · Урок

Трансляция сообщений

Отправляйте сообщения множеству клиентов

«Трансляция сообщений» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Основы WebSocket
  2. Использование gorilla/websocket
  3. Трансляция сообщений
  4. Управление соединениями
← Назад к Go Academy