メッセージのブロードキャスト
多数のクライアントに送信します
「メッセージのブロードキャスト」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
多数のクライアントへの送信
チャットルームやライブフィードでは、1つのメッセージを接続中のすべてのクライアントに送信する必要があります。各WebSocketではライターを1つしか使えないため、調整パターンであるハブが必要です。
ハブパターン
ハブとは、クライアントの集合とブロードキャスト用のチャネルを所有する中央のgoroutineです。クライアントは登録・登録解除を行い、ハブがメッセージを各クライアントに分配します。複数のgoroutineが共有mapを直接操作することはありません。
ハブのデータ構造
ハブは次のものを保持します。
- クライアントの集合(
map[*Client]bool) - メッセージ用の
broadcastチャネル registerチャネルとunregisterチャネル
type Hub struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unregister chan *Client
}ハブの実行ループ
1つのRun goroutineがチャネルをselectします。mapを変更するのがこのgoroutineだけであるため、mutexは必要ありません。
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を持ちます。ハブはそこに書き込み、専用のライターgoroutineがそこから取り出してソケットに書き込みます。これにより、ライターを1つだけにするルールを守れます。
type Client struct {
conn *websocket.Conn
send chan []byte
}ライターgoroutine
各クライアントは、sendをrangeで読み取り、ソケットに書き込むwritePumpを実行します。チャネルが閉じられると、closeフレームを送信します。
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)
}mutexではなくチャネルを使う理由
Goのモットーは「通信によってメモリを共有する」です。チャネルを介してすべての変更を1つのgoroutineに集約すれば、明示的なロックを使わずにクライアントmapの競合状態を防げます。
メッセージのブロードキャスト
どのハンドラからでもハブのチャネルに送信してブロードキャストできます。ハブが登録済みのすべてのクライアントに分配します。
hub.broadcast <- []byte("server announcement")特定クライアントへの送信とブロードキャスト
ルームやダイレクトメッセージでは、クライアントをルームIDやユーザーIDをキーにして保持し、すべてのクライアントではなく関係する部分集合だけを反復処理します。これにより、多数のルームがあるチャットでも効率を保てます。
実行例:チャネルによる分配
この自己完結型プログラムは、標準ライブラリとgoroutineだけを使って、ハブが1つのメッセージを複数のクライアント用チャネルに分配する様子をモデル化します。
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()
}理解度チェック
ブロードキャストについて理解度を確認しましょう。
まとめ
多数のクライアントへのブロードキャスト方法を学びました。
- ハブgoroutineがクライアントの集合とブロードキャストチャネルを所有します
- 各クライアントには、ライターgoroutineが読み出すバッファ付きの送信用チャネルがあります
- これにより、接続ごとにライターを1つだけにするルールを守れます
- 遅いクライアントを切断して、ハブの応答性を保ちます
よくある質問
「メッセージのブロードキャスト」レッスンは無料ですか?
はい。「メッセージのブロードキャスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「メッセージのブロードキャスト」で何を学びますか?
多数のクライアントに送信します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「メッセージのブロードキャスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- WebSocketの基礎
- gorilla/websocketの使用
- メッセージのブロードキャスト
- 接続管理