04/03/2026 08:45น.

EP.114 การจัดการ Multi-device & Multi-session สำหรับ WebSocket Server
#WebSocket Server
#Real-time System
#Go
#Multi-session
#Multi-device
#WebSocket
ในแอปพลิเคชันแบบเรียลไทม์ ไม่ว่าจะเป็นระบบแชท, การแจ้งเตือน, หรือเกม ผู้ใช้ 1 คนอาจล็อกอินจากหลายอุปกรณ์ได้พร้อมกัน เช่น มือถือและเดสก์ท็อป 💻📱
หากระบบ WebSocket ไม่รองรับ Multi-device หรือ Multi-session อย่างถูกต้อง อาจเกิดปัญหา Sync ไม่ทัน, ข้อมูลซ้ำซ้อน หรือ session รั่ว
ใน EP นี้ เราจะพาคุณเรียนรู้การออกแบบระบบ WebSocket ที่
- รองรับผู้ใช้หลายอุปกรณ์พร้อมกัน
- จัดการ session แยกกันอย่างปลอดภัย
- ซิงก์ข้อมูลระหว่างอุปกรณ์แบบเรียลไทม์
- พร้อมใช้งานจริงในระดับ Production
🔍 ปัญหาที่พบบ่อยเมื่อมีหลาย Session
| ปัญหา | คำอธิบาย |
|---|---|
| Session ซ้ำ | ผู้ใช้เปิดหลายอุปกรณ์พร้อมกัน ทำให้เกิดข้อความซ้ำ |
| Connection Leak | session เดิมไม่ถูกปิดเมื่อมีอุปกรณ์ใหม่เชื่อมต่อ |
| Token หมดอายุ | ไม่จัดการ refresh token อย่างเหมาะสม ทำให้หลุดการเชื่อมต่อ |
| Sync ล่าช้า | ข้อมูลอัปเดตไม่พร้อมกันทุกอุปกรณ์ |
แนวทางที่ดี: อุปกรณ์แต่ละเครื่องควรมี session แยก แต่ Sync ข้อมูลเหมือนกัน
🧩 โครงสร้าง Session ใน WebSocket
type Session struct {
UserID string
DeviceID string
Connection *websocket.Conn
}
var (
activeSessions = make(map[string]map[string]*Session) // userID → deviceID → session
mu sync.Mutex
)
✅ ผู้ใช้ 1 คนสามารถมีหลายอุปกรณ์
✅ ทุกอุปกรณ์มี session แยกกัน
✅ สามารถส่งข้อความเฉพาะเครื่อง หรือ broadcast ทุก session ได้
🔌 ตัวอย่างการเชื่อมต่อจากหลายอุปกรณ์
func handleConnection(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
userID := r.URL.Query().Get("user_id")
deviceID := r.URL.Query().Get("device_id")
mu.Lock()
if activeSessions[userID] == nil {
activeSessions[userID] = make(map[string]*Session)
}
activeSessions[userID][deviceID] = &Session{
UserID: userID,
DeviceID: deviceID,
Connection: conn,
}
mu.Unlock()
defer func() {
mu.Lock()
delete(activeSessions[userID], deviceID)
if len(activeSessions[userID]) == 0 {
delete(activeSessions, userID)
}
mu.Unlock()
conn.Close()
}()
for {
_, msg, err := conn.ReadMessage()
if err != nil {
break
}
log.Printf("[%s-%s]: %s", userID, deviceID, msg)
}
}
✅ เมื่ออุปกรณ์ใดหลุดออก จะลบ session อัตโนมัติ
✅ ไม่มี session ค้างในระบบ
🔐 การตรวจสอบ Token และ Session
func validateToken(token string) (string, error) {
claims := &jwt.StandardClaims{}
_, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
return []byte("SECRET_KEY"), nil
})
if err != nil {
return "", err
}
return claims.Subject, nil
}
- ทุกอุปกรณ์ควรใช้ token ของตัวเอง
- refresh token แยกตามอุปกรณ์
- ถ้า token หมดอายุ → ตัดการเชื่อมต่อเฉพาะเครื่องนั้น
🌐 การ Sync ข้อมูลระหว่างอุปกรณ์
func syncToAllDevices(userID string, message string) {
mu.Lock()
defer mu.Unlock()
for _, session := range activeSessions[userID] {
session.Connection.WriteMessage(websocket.TextMessage, []byte(message))
}
}
✅ ส่งข้อความจากมือถือ → ขึ้นบนคอมพร้อมกัน
✅ Sync ข้ามอุปกรณ์แบบเรียลไทม์
✅ รองรับการใช้งานในระบบ Production ได้จริง
🧱 แนวทางระดับ Production
| หมวด | แนวทาง |
|---|---|
| Session Storage | ใช้ Redis หรือ DB จัดเก็บ session |
| Security | ผูก Token กับ Device ID |
| Sync | Redis Pub/Sub กระจายข้อมูล |
| Timeout | ลบ session ที่ idle เกินเวลา |
| Monitoring | ติดตามจำนวนอุปกรณ์ต่อผู้ใช้ |
🚀 ท้าให้ลอง!
ลองเขียนระบบที่ให้ผู้ใช้ 1 คนเปิดทั้งมือถือและคอม ส่งข้อความจากเครื่องหนึ่ง → อีกเครื่องต้องอัปเดตทันที
ถ้าทำได้สำเร็จ คุณกำลังสร้างระบบแบบเดียวกับที่องค์กรใหญ่ใช้จริงแล้วในวันนี้ ✅
🌟 EP ถัดไป: ระบบ Multiplayer Game ขั้นสูง (EP.115)
ใน EP.115 เราจะพาไปสู่โลกของเกมแบบหลายผู้เล่น เรียนรู้การ sync ผู้เล่น, event, และตำแหน่งในเกมแบบ real-time ด้วย Go และ WebSocket เพื่อให้คุณพร้อมสร้างเกมหรือระบบแบบ Interactive ได้แบบมืออาชีพ! 🎮