WebSocket คืออะไร?
ในบทเรียนแรกเราบอกว่า WebSocket คือ การเชื่อมต่อแบบ persistent และ full-duplex เส้นเดียว บทเรียนนี้จะค่อย ๆ เจาะว่า ทำไมประโยคเดียวนี้ถึงเปลี่ยนวิธีที่คุณสร้างซอฟต์แวร์ — พร้อมให้ลองสัมผัสจริงด้วยเดโมสดอีกอัน
การเชื่อมต่อเส้นเดียว ไม่ใช่หลายเส้น
หัวข้อที่มีชื่อว่า “การเชื่อมต่อเส้นเดียว ไม่ใช่หลายเส้น”ลองนึกภาพว่าเบราว์เซอร์คุยกับ server ตามปกติอย่างไร ทุกการโต้ตอบคือธุระแยกกันที่จบในตัวเอง:
- เปิดการเชื่อมต่อ (หรือยืมจาก pool ที่มีอยู่)
- ส่ง request
- รับ response
- การแลกเปลี่ยนจบลง server ลืมคุณไป
ถ้าหน้าหนึ่งต้องการข้อมูลสิบชิ้น นั่นก็คือสิบธุระในเชิงแนวคิด แต่ละธุระแบก header ของตัวเอง แบกต้นทุนการตั้งต้นของตัวเอง และ — ที่สำคัญ — ไหลไปในทิศทางที่ client เป็นคนเริ่มเท่านั้น server พูดก่อนไม่ได้ ทำได้แค่ตอบ
WebSocket แทนที่รูปแบบทั้งหมดนั้นด้วยสายเปิดเส้นเดียว:
flowchart TB
subgraph http["HTTP — many short exchanges"]
direction LR
c1["client"] -- "req 1" --> s1["server"]
s1 -- "res 1" --> c1
c2["client"] -- "req 2" --> s2["server"]
s2 -- "res 2" --> c2
c3["client"] -- "req 3" --> s3["server"]
s3 -- "res 3" --> c3
end
subgraph ws["WebSocket — one persistent connection"]
direction LR
cw["client"] <--> sw["server"]
end เมื่อสายนั้นเปิดแล้ว การส่งข้อความก็ถูก: ไม่มีการเชื่อมต่อใหม่ให้ต้องเจรจา และไม่มี header overhead ต่อ request และเพราะสายนั้นเป็นสองทางอย่างแท้จริง server จึงส่งข้อความได้ทันทีที่มีอะไรเกิดขึ้น — บรรทัดแชตใหม่ ราคาที่เปลี่ยนไป การแก้ไขของผู้ใช้คนอื่น — โดยที่ client ไม่เคยต้องร้องขอเลย
ความแตกต่างที่นิยามทุกอย่าง
หัวข้อที่มีชื่อว่า “ความแตกต่างที่นิยามทุกอย่าง”จะเห็นภาพชัดขึ้นถ้าวางทั้งสองแบบเทียบกันเป็นร้อยแก้วธรรมดาแทนไดอะแกรม:
- HTTP request/response คือ client เป็นผู้เริ่มและจบในครั้งเดียว client ถาม server ตอบ จบ การจะรู้เรื่องเหตุการณ์ใหม่ client ต้องถามอีกครั้ง
- WebSocket คือ ฝ่ายใดฝ่ายหนึ่งเริ่มได้และต่อเนื่อง หลังการตั้งต้นครั้งเดียว ทั้งสองปลายถือการเชื่อมต่อเดิมเปิดค้างไว้ แล้ว push message ข้ามไปมาได้นานเท่าที่ต้องการ
การเปลี่ยนผ่านนั้น — จาก “ถามซ้ำแล้วซ้ำเล่า” ไปสู่ “เชื่อมต่อค้างไว้แล้วฟัง” — คือคุณค่าทั้งหมดที่นำเสนอ
จุดที่ WebSocket โดดเด่น
หัวข้อที่มีชื่อว่า “จุดที่ WebSocket โดดเด่น”WebSocket คือเครื่องมือที่ถูกต้องเมื่อใดก็ตามที่ server ต้อง push ข้อมูลที่ client ไม่อาจคาดเดาล่วงหน้าได้:
- แชตและการส่งข้อความ — ข้อความจากผู้ใช้คนหนึ่งต้องไปถึงคนอื่นทันที โดยไม่ต้อง polling
- ฟีดข้อมูลสด — ราคา คะแนน ค่าจากเซ็นเซอร์ แดชบอร์ดที่อัปเดตตามโลกที่เปลี่ยนไป
- การทำงานร่วมกัน — เอกสารที่แชร์กัน ไวต์บอร์ด และเครื่องมือออกแบบที่ทุกการกดแป้นหรือการเลื่อนเคอร์เซอร์ส่งต่อไปยังทุกคน
- การแจ้งเตือนและสถานะการมีอยู่ — “มีออเดอร์ใหม่เข้ามา”, “Sam กำลังพิมพ์”, “บิลด์ของคุณเสร็จแล้ว”
- มัลติเพลเยอร์และเกม — การอัปเดตสถานะที่ latency ต่ำ พุ่งไปมาทั้งสองทางหลายครั้งต่อวินาที
เส้นด้ายร่วมกัน: เหตุการณ์เกิดขึ้นที่ฝั่ง server ในเวลาที่คาดเดาไม่ได้ และ latency มีความสำคัญ นั่นคือช่องว่างที่การเชื่อมต่อแบบ persistent และ bidirectional เข้ามาเติมเต็มพอดี
ลองสัมผัสของจริง
หัวข้อที่มีชื่อว่า “ลองสัมผัสของจริง”ลองรันเดโมข้างล่าง เดโมใช้ in-page echo socket ที่มี WebSocket API ของจริง — มี onopen/onmessage/send/close ครบ — จึงรันได้ทุกที่โดยไม่ต้องมี server เดโมส่งไปหนึ่งบรรทัดแล้วพิมพ์สิ่งที่ตอบกลับมา สังเกตว่าหลัง open เพียงครั้งเดียว การเชื่อมต่อก็แค่ นั่งพร้อมอยู่ตรงนั้น — คุณส่งอีกได้ทุกเมื่อโดยไม่ต้องเชื่อมต่อใหม่
บรรทัด received: แรกคือคำทักทายของ server ตอนเชื่อมต่อ ส่วนบรรทัดที่สองคือข้อความของเราเองที่ถูก echo กลับมา เราปิดก็ต่อเมื่อข้อความที่สองมาแล้วเท่านั้น — เป็นการพิสูจน์ว่าการเชื่อมต่อเปิดค้างและใช้งานได้ตลอดเวลา นั่นคือสิ่งที่ HTTP request/response ให้ไม่ได้เลย
| ข้อดี (WebSocket) | ข้อแลกเปลี่ยน |
|---|---|
| latency ต่ำมาก — ไม่มี HTTP overhead ต่อ message | server ต้องเก็บ state ต่อ connection — ไม่ stateless เหมือน HTTP |
| bidirectional — server push ได้ทันที | connection ที่เปิดค้างกิน memory ต่อ user |
| ไม่มี polling overhead — ส่งเฉพาะเมื่อมี event | scaling ยากกว่า REST API — ต้องจัดการ sticky session |
| ลด HTTP request — ประหยัด bandwidth | ไม่ cacheable — CDN ช่วยไม่ได้ |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”ใช้ WebSocket สำหรับ Operation ที่ HTTP เหมาะกว่า อาการ:
- ใช้ WebSocket สำหรับ form submit, file upload, data fetch ครั้งเดียว
- complexity สูงโดยไม่ได้ benefit จาก real-time
- ใช้ WebSocket เฉพาะเมื่อต้องการ server push หรือ bidirectional low-latency
ไม่มี Reconnect Logic อาการ:
- connection ขาด → app หยุดทำงานโดยไม่แจ้ง user
- user ต้อง refresh หน้าเพื่อเชื่อมต่อใหม่
- implement
onclosehandler ที่ reconnect อัตโนมัติด้วย exponential backoff
💡 ตัวอย่างจากของจริง
Discord:
- WebSocket สำหรับ real-time message, presence, voice state
- fallback ไปยัง long polling เมื่อ WebSocket ไม่ available
Slack:
- RTM (Real Time Messaging) API ผ่าน WebSocket
- ทุก message, reaction, typing indicator ส่งผ่าน WebSocket connection เดียว