[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"academy-blogs-th-1-1-all-golang-multi-room-chat-websocket-all--*":3,"academy-blog-translations-mkt01wcars4seqi":74},{"data":4,"page":62,"perPage":62,"totalItems":62,"totalPages":62},[5],{"alt":6,"collectionId":7,"collectionName":8,"content":9,"cover_image":10,"cover_image_path":11,"created":12,"created_by":13,"expand":14,"id":68,"keywords":69,"locale":44,"published_at":70,"scheduled_at":13,"school_blog":66,"short_description":71,"slug":72,"status":64,"title":6,"updated":73,"updated_by":13,"views":67},"EP.88 การสร้างระบบแชทรองรับหลายห้อง (Multi-room Chat Management)","sclblg987654321","school_blog_translations","\u003Cp>WebSocket Chat ที่ดี ไม่ใช่แค่การเปิดให้ผู้ใช้เชื่อมต่อ แต่ต้องสามารถรองรับระบบ “หลายห้องแชท” หรือ Multi-room Chat เพื่อให้ผู้ใช้สามารถแยกกลุ่ม ส่งข้อความภายในกลุ่ม และจัดการสมาชิกแต่ละห้องได้อย่างมีประสิทธิภาพ\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>ในบทความนี้ เราจะมาเรียนรู้การสร้างระบบ Multi-room Chat อย่างเป็นระบบด้วย Golang + WebSocket พร้อมเทคนิคจัดการสมาชิกและสื่อสารแบบเรียลไทม์อย่างปลอดภัยและมีประสิทธิภาพ\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🔧 โครงสร้างหลักของระบบหลายห้อง\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>ระบบจะประกอบด้วย 3 องค์ประกอบหลัก:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">type Client struct {\n    ID     string\n    Conn   *websocket.Conn\n    RoomID string\n    Send   chan []byte\n}\n\ntype Room struct {\n    ID        string\n    Clients   map[string]*Client\n    Broadcast chan []byte\n}\n\ntype Hub struct {\n    Rooms      map[string]*Room\n    Register   chan *Client\n    Unregister chan *Client\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>\u003Ccode inline=\"\">Client\u003C\u002Fcode>: ตัวแทนของผู้ใช้แต่ละราย พร้อมข้อมูลการเชื่อมต่อและห้องที่เข้าร่วม\u003C\u002Fli>\u003Cli>\u003Ccode inline=\"\">Room\u003C\u002Fcode>: ห้องแชทแต่ละห้องที่เก็บผู้ใช้และช่องสำหรับส่งข้อความ (Broadcast)\u003C\u002Fli>\u003Cli>\u003Ccode inline=\"\">Hub\u003C\u002Fcode>: ตัวกลางรวมทุกห้อง ทำหน้าที่จัดการการเข้า-ออกของสมาชิก\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🧩 การลงทะเบียน\u002Fออกจากห้องของผู้ใช้\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">func (h *Hub) Run() {\n    for {\n        select {\n        case client := &lt;-h.Register:\n            room, ok := h.Rooms[client.RoomID]\n            if !ok {\n                room = &amp;Room{\n                    ID:        client.RoomID,\n                    Clients:   make(map[string]*Client),\n                    Broadcast: make(chan []byte),\n                }\n                h.Rooms[client.RoomID] = room\n                go room.Run()\n            }\n            room.Clients[client.ID] = client\n\n        case client := &lt;-h.Unregister:\n            if room, ok := h.Rooms[client.RoomID]; ok {\n                delete(room.Clients, client.ID)\n                close(client.Send)\n                if len(room.Clients) == 0 {\n                    delete(h.Rooms, room.ID)\n                }\n            }\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>\u003Ccode inline=\"\">Register\u003C\u002Fcode>: เพิ่มผู้ใช้เข้าในห้อง หากห้องยังไม่ถูกสร้าง จะสร้างห้องใหม่โดยอัตโนมัติ\u003C\u002Fli>\u003Cli>\u003Ccode inline=\"\">Unregister\u003C\u002Fcode>: ลบผู้ใช้ออกจากห้อง และลบห้องหากไม่มีสมาชิกเหลือ\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>📢 การกระจายข้อความภายในห้อง\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">func (r *Room) Run() {\n    for {\n        select {\n        case message := &lt;-r.Broadcast:\n            for _, client := range r.Clients {\n                select {\n                case client.Send &lt;- message:\n                default:\n                    close(client.Send)\n                    delete(r.Clients, client.ID)\n                }\n            }\n        }\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>ข้อความใดที่ถูกส่งเข้ามาใน \u003Ccode inline=\"\">Broadcast\u003C\u002Fcode> จะถูกกระจายไปยังสมาชิกในห้องนั้นทันที\u003C\u002Fli>\u003Cli>หากส่งไม่ทัน จะปิดช่องสื่อสารของ client เพื่อลดการค้าง\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🔄 การรับ\u002Fส่งข้อความของแต่ละ Client\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">func (c *Client) ReadPump(h *Hub) {\n    defer func() {\n        h.Unregister &lt;- c\n        c.Conn.Close()\n    }()\n    for {\n        _, msg, err := c.Conn.ReadMessage()\n        if err != nil {\n            break\n        }\n        if room, ok := h.Rooms[c.RoomID]; ok {\n            room.Broadcast &lt;- msg\n        }\n    }\n}\n\nfunc (c *Client) WritePump() {\n    for msg := range c.Send {\n        c.Conn.WriteMessage(websocket.TextMessage, msg)\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cul>\u003Cli>\u003Ccode inline=\"\">ReadPump\u003C\u002Fcode>: รับข้อความจาก client แล้วส่งต่อให้ room broadcast\u003C\u002Fli>\u003Cli>\u003Ccode inline=\"\">WritePump\u003C\u002Fcode>: รับข้อความจาก room แล้วส่งกลับไปยัง client\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>👥 การจัดการสมาชิกในห้อง\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>เพิ่มฟีเจอร์เช่นการแสดงรายชื่อผู้ใช้ในห้อง (List Members):\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-go\">func (r *Room) ListMembers() []string {\n    members := []string{}\n    for id := range r.Clients {\n        members = append(members, id)\n    }\n    return members\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>และสามารถสร้าง API endpoint เช่น \u003Ccode inline=\"\">\u002Fjoin-room\u003C\u002Fcode>, \u003Ccode inline=\"\">\u002Fleave-room\u003C\u002Fcode>, \u003Ccode inline=\"\">\u002Fmembers\u003C\u002Fcode> เพื่อควบคุมผ่าน frontend ได้\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🧠 แนวทางการนำไปใช้ใน Production\u003C\u002Fh2>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cul>\u003Cli>✅ ใช้ Redis Pub\u002FSub เพื่อแชร์ข้อความระหว่างหลาย instance\u003C\u002Fli>\u003Cli>✅ ตั้งค่าจำกัดจำนวนผู้ใช้ต่อห้อง (Connection Limit per Room)\u003C\u002Fli>\u003Cli>✅ เปิดใช้งาน Gzip Compression เพื่อลดขนาด Payload\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Chr>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🚀 ท้าให้ลอง!\u003C\u002Fh2>\u003Cul>\u003Cli>ลองสร้างระบบ Multi-room Chat ของคุณเอง\u003C\u002Fli>\u003Cli>เพิ่มฟีเจอร์เพิ่มเติม เช่น:\u003Cul>\u003Cli>ห้องแบบ Private\u003C\u002Fli>\u003Cli>Room Admin\u003C\u002Fli>\u003Cli>การแจ้งเตือนเมื่อมีผู้เข้าร่วมหรือออก\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>&nbsp;\u003C\u002Fp>\u003Ch2>🔜 EP ถัดไป\u003C\u002Fh2>\u003Cp>EP.89: การทดสอบประสิทธิภาพ WebSocket Server ด้วยเครื่องมือ Load Testing\u003C\u002Fp>\u003Cp>มาดูกันว่าระบบ WebSocket ของคุณสามารถรับโหลดระดับสูงได้แค่ไหน และเรียนรู้การใช้เครื่องมือสำหรับ Benchmark ระบบแบบมือโปร!\u003C\u002Fp>\u003Cp>&nbsp;\u003C\u002Fp>\u003Cp>\u003Cstrong>อ่านบทความ Series อื่นๆ\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fblogs\u002Fcategories\u002FGolang\">\u003Cstrong>Golang The Series\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fblogs\u002Fcategories\u002FJS2GO\">\u003Cstrong>JS2GO\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fli>\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdev.school\u002Fblogs\u002Fcategories\u002FTailwind%20CSS\">\u003Cstrong>10 Ep ที่จะให้คุณเป็นมือโปร Tailwind CSS ในชั่วข้ามคืน\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>🔵 Facebook: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\">\u003Cstrong>https:\u002F\u002Fwww.facebook.com\u002Fsuperdev.academy.th\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>🔴 YouTube : \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUC2eI2RxcA2zbTqZyHyWIfRg\">\u003Cstrong>Superdev Academy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>📸 Instagram: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.instagram.com\u002Fsuperdevschool\u002F\">\u003Cstrong>Superdev Academy\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>🎬 TikTok: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\">\u003Cstrong>https:\u002F\u002Fwww.tiktok.com\u002F@superdevacademy?lang=th-TH\u003C\u002Fstrong>\u003C\u002Fa>\u003C\u002Fp>\u003Cp>\u003Cstrong>🌐 Website: \u003C\u002Fstrong>\u003Ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"https:\u002F\u002Fwww.superdevacademy.com\u002F\">\u003Cstrong>https:\u002F\u002Fwww.superdevacademy.com\u002F\u003C\u002Fstrong>\u003C\u002Fa>\u003Cstrong>&nbsp;\u003C\u002Fstrong>\u003C\u002Fp>","147_11zon_p7l1ry1jfk.webp","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclblg987654321\u002Ftajob8clmkaq6gs\u002F147_11zon_p7l1ry1jfk.webp","2026-03-04 08:46:51.703Z","",{"keywords":15,"locale":38,"school_blog":48},[16,23,28,33],{"collectionId":17,"collectionName":18,"created":19,"created_by":13,"id":20,"name":21,"updated":22,"updated_by":13},"sclkey987654321","school_keywords","2026-03-04 08:34:00.920Z","ecac9y661or1xka","WebSocket","2026-04-10 16:08:05.227Z",{"collectionId":17,"collectionName":18,"created":24,"created_by":13,"id":25,"name":26,"updated":27,"updated_by":13},"2026-03-04 08:20:14.253Z","ah6lvy4x8qe08l5","Golang","2026-04-10 16:07:26.172Z",{"collectionId":17,"collectionName":18,"created":29,"created_by":13,"id":30,"name":31,"updated":32,"updated_by":13},"2026-03-04 08:20:11.547Z","ey3puyme01a9bsw","Go","2026-04-10 16:07:25.893Z",{"collectionId":17,"collectionName":18,"created":34,"created_by":13,"id":35,"name":36,"updated":37,"updated_by":13},"2026-03-04 08:46:51.136Z","rbaifonz0tg1ehh","ระบบแชท","2026-04-10 16:13:20.059Z",{"code":39,"collectionId":40,"collectionName":41,"created":42,"flag":43,"id":44,"is_default":45,"label":46,"updated":47},"th","pbc_1989393366","locales","2026-01-22 10:59:55.832Z","twemoji:flag-thailand","s8wri3bt4vgg2ji",true,"Thai","2026-04-10 15:42:46.614Z",{"category":49,"collectionId":50,"collectionName":51,"expand":52,"id":66,"views":67},"wqxt7ag2gn7xcmk","pbc_2105096300","school_blogs",{"category":53},{"blogIds":54,"collectionId":55,"collectionName":56,"created":57,"created_by":13,"id":49,"image":58,"image_alt":13,"image_path":59,"label":60,"name":61,"priority":62,"publish_at":63,"scheduled_at":13,"status":64,"updated":65,"updated_by":13},[],"sclcatblg987654321","school_category_blogs","2026-03-04 08:33:53.210Z","59ty92ns80w_15oc1implw.png","https:\u002F\u002Ftwsme-r2.tumwebsme.com\u002Fsclcatblg987654321\u002Fwqxt7ag2gn7xcmk\u002F59ty92ns80w_15oc1implw.png",{"en":61,"th":61},"Golang The Series",1,"2026-03-16 04:39:38.440Z","published","2026-04-25 02:32:15.470Z","mkt01wcars4seqi",230,"tajob8clmkaq6gs",[20,25,30,35],"2025-09-09 02:03:12.924Z","เรียนรู้การสร้างระบบแชทแบบหลายห้องด้วยภาษา Go และ WebSocket พร้อมตัวอย่างโค้ดเต็ม การจัดการสมาชิกแต่ละห้อง การกระจายข้อความ และแนวทางนำไปใช้งานจริง","golang-multi-room-chat-websocket","2026-04-25 02:48:09.156Z",{"th":72}]