0Pricing
Go Academy · บทเรียน

การกระจายข้อความ

ส่งไปยังไคลเอนต์หลายราย

การกระจายข้อความ เป็นบทเรียน Go Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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")

การส่งแบบเจาะจงกับการกระจายทั้งหมด

สำหรับห้องแชตหรือข้อความส่วนตัว ให้จัดเก็บไคลเอ็นต์โดยใช้รหัสห้องหรือรหัสผู้ใช้เป็นคีย์ แล้ววนดูเฉพาะกลุ่มย่อยที่เกี่ยวข้องแทนการวนดูไคลเอ็นต์ทั้งหมด วิธีนี้ช่วยให้แชตที่มีหลายห้องยังทำงานได้อย่างมีประสิทธิภาพ

ตัวอย่างที่รันได้: กระจายข้อมูลด้วยช่องสัญญาณ

โปรแกรมนี้ทำงานได้ในตัวและจำลองฮับที่กระจายข้อความหนึ่งข้อความไปยังช่องสัญญาณของไคลเอ็นต์หลายราย โดยใช้เฉพาะไลบรารีมาตรฐานและกอรูทีน

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()
}

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจเรื่องการกระจายข้อความ

สรุปทบทวน

คุณได้เรียนรู้การกระจายข้อความไปยังไคลเอ็นต์หลายรายดังนี้:

  • กอรูทีนฮับเป็นเจ้าของชุดไคลเอ็นต์และช่องสัญญาณสำหรับกระจายข้อความ
  • ไคลเอ็นต์แต่ละรายมีช่องสัญญาณส่งข้อมูลแบบมีบัฟเฟอร์ ซึ่งกอรูทีนตัวเขียนจะดึงข้อมูลออกไป
  • วิธีนี้สอดคล้องกับกฎตัวเขียนหนึ่งตัวต่อการเชื่อมต่อหนึ่งรายการ
  • ยกเลิกไคลเอ็นต์ที่ช้าเพื่อให้ฮับยังตอบสนองได้

คำถามที่พบบ่อย

บทเรียน “การกระจายข้อความ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การกระจายข้อความ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Go Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Go Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การกระจายข้อความ”

ส่งไปยังไคลเอนต์หลายราย คุณปฏิบัติ Go Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 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