Signaling Server — คือองค์ประกอบเซิร์ฟเวอร์ของโครงสร้างพื้นฐาน WebRTC ที่อำนวยความสะดวกในการแลกเปลี่ยนข้อมูลเมตาระหว่างเพียร์เพื่อสร้างและยุติการเชื่อมต่อ ซึ่งแตกต่างจากทราฟฟิกสื่อ การส่งสัญญาณสามารถส่งผ่านโปรโตคอลใดก็ได้ — WebSocket, HTTP, XMPP หรือ SIP ตาม MDN Web Docs, 2024 การส่งสัญญาณเป็นองค์ประกอบบังคับของแอปพลิเคชัน WebRTC ใดๆ เนื่องจากโปรโตคอลไม่ได้กำหนดวิธีการเฉพาะสำหรับการแลกเปลี่ยนข้อความส่งสัญญาณ
ประเด็นสำคัญ
Signaling Server — คือบริการเครือข่ายที่รับผิดชอบในการประสานงานกระบวนการสร้างการเชื่อมต่อ WebRTC ระหว่างเพียร์ตั้งแต่สองตัวขึ้นไป มันไม่ส่งข้อมูลสื่อ (เสียง วิดีโอ ข้อมูล DataChannel) แต่ส่งเฉพาะข้อมูลควบคุมที่จำเป็นสำหรับการค้นหาเพียร์และการเจรจาพารามิเตอร์การเชื่อมต่อ หลังจากสร้างช่องทาง P2P สำเร็จแล้ว อาจไม่จำเป็นต้องใช้ Signaling Server อีกต่อไป แต่ในสถาปัตยกรรมบางอย่าง มันยังคงอยู่สำหรับการแลกเปลี่ยนสัญญาณในภายหลัง (เช่น การยุติการโทร การเพิ่มผู้เข้าร่วม)
สถาปัตยกรรมการส่งสัญญาณประกอบด้วยสามองค์ประกอบ: Signaling Server, Signal Channel (โปรโตคอลขนส่งระหว่างไคลเอ็นต์และเซิร์ฟเวอร์) และ API ของไคลเอ็นต์ (มักรวมอยู่ในสแตก WebRTC ของเบราว์เซอร์) ข้อกำหนด WebRTC (W3C, 2024) จงใจไม่กำหนดมาตรฐานโปรโตคอลการส่งสัญญาณ — นักพัฒนาสามารถเลือกการขนส่งที่เหมาะสมกับแอปพลิเคชันของตนได้ วิธีการที่ยืดหยุ่นนี้ช่วยให้ใช้ WebSocket สำหรับแอปพลิเคชันเว็บ XMPP สำหรับระบบแชท หรือ SIP สำหรับการรวมเข้ากับโครงสร้างพื้นฐานโทรคมนาคม
ก่อนสร้างการเชื่อมต่อ WebRTC เพียร์ต้องแลกเปลี่ยนข้อความสามประเภท: คำอธิบายเซสชัน (offer และ answer), ผู้สมัคร ICE และข้อมูลการยุติ/แก้ไขเซสชัน Signaling Server จะกำหนดเส้นทางข้อความเหล่านี้ระหว่างเพียร์โดยใช้ตัวระบุห้องหรือผู้ใช้สำหรับการระบุตำแหน่ง รูปแบบมาตรฐานคือการสร้าง “ห้อง” ที่ผู้เข้าร่วมสองคนเชื่อมต่อ และเซิร์ฟเวอร์จะถ่ายทอดข้อความจากผู้เข้าร่วมแต่ละคนไปยังคู่สนทนาของพวกเขาเท่านั้น
Signaling Server ใช้โปรโตคอลการสร้างการเชื่อมต่อ WebRTC ทั่วไปดังต่อไปนี้ เพียร์เชื่อมต่อกับเซิร์ฟเวอร์ผ่าน WebSocket (หรือการขนส่งอื่น) และลงทะเบียนในห้อง เพียร์ A (ผู้เริ่มต้น) สร้าง offer (คำอธิบาย SDP ของสตรีมสื่อขาออก) ผ่าน RTCPeerConnection.createOffer() ตั้งค่าเป็นคำอธิบายในเครื่องและส่งไปยัง Signaling Server เซิร์ฟเวอร์ถ่ายทอด offer ไปยังเพียร์ B เพียร์ B รับ offer ตั้งค่าเป็นคำอธิบายระยะไกล สร้าง answer ผ่าน createAnswer() ตั้งค่าเป็นคำอธิบายในเครื่องและส่งกลับผ่านเซิร์ฟเวอร์ กระบวนการนี้เรียกว่า SDP Offer/Answer
ควบคู่ไปกับการแลกเปลี่ยน SDP เพียร์แต่ละตัวรวบรวมผู้สมัคร ICE (host, srflx, relay) และส่งผ่าน Signaling Server ไปยังเพียร์อื่น เพียร์ระยะไกลเพิ่มผู้สมัครที่ได้รับผ่าน RTCPeerConnection.addIceCandidate() กระบวนการ ICE ทดสอบการรวมกันของผู้สมัครทั้งหมดเพื่อค้นหาเส้นทางที่ใช้งานได้ เมื่อพบเส้นทางที่ใช้งานได้ (โดยปกติภายใน 1–5 วินาที) ทราฟฟิกสื่อเริ่มไหลโดยตรงระหว่างเพียร์ และ Signaling Server ไม่มีส่วนร่วมในการส่งข้อมูลอีกต่อไป — บทบาทของมันสิ้นสุดลงจนกว่าจะมีเหตุการณ์ควบคุมถัดไป (การยุติการโทร การเปลี่ยนคุณภาพสตรีม)
สำหรับการระบุตำแหน่งข้อความ Signaling Server ใช้กลไกห้องหรือช่องทาง แต่ละเซสชัน WebRTC ใหม่สร้างห้องที่ไม่ซ้ำกันด้วยตัวระบุ (โดยปกติคือ UUID) ผู้เริ่มต้นสร้างห้องและรอการเชื่อมต่อของเพียร์ที่สอง เพียร์ที่สองเข้าร่วมห้องโดยใช้ ID ที่ได้รับผ่านช่องทางภายนอก (เช่น ลิงก์เชิญ) เซิร์ฟเวอร์รักษาแผนที่ของห้อง โดยแต่ละ ID สอดคล้องกับรายการของไคลเอ็นต์ที่เชื่อมต่อ เมื่อจำนวนผู้เข้าร่วมถึงสองคน เซิร์ฟเวอร์เริ่มถ่ายทอดข้อความส่งสัญญาณระหว่างพวกเขา
Signaling Server สามารถใช้โปรโตคอลขนส่งที่แตกต่างกัน โดยแต่ละโปรโตคอลมีข้อดีและข้อเสียของตัวเอง การเลือกโปรโตคอลขึ้นอยู่กับประเภทของแอปพลิเคชัน ข้อจำกัดของโครงสร้างพื้นฐาน และข้อกำหนดความเข้ากันได้ ด้านล่างนี้คือโปรโตคอลที่พบบ่อยที่สุดและคุณลักษณะของพวกเขา
| โปรโตคอล | การขนส่ง | ข้อดี | ข้อเสีย |
|---|---|---|---|
| WebSocket | TCP | ฟูลดูเพล็กซ์ หน่วงเวลาต่ำ ในตัวในเบราว์เซอร์ | ความซับซ้อนในการปรับขนาด การบล็อกพร็อกซี |
| HTTP/SSE | TCP | เข้ากันได้กับโครงสร้างพื้นฐานใดๆ ใช้งานง่าย | ทิศทางเดียวเท่านั้น (เซิร์ฟเวอร์-ไคลเอ็นต์) ต้องมีการสอบถาม |
| XMPP | TCP | ได้มาตรฐาน รองรับการตรวจสอบสิทธิ์ ขยายได้ | มากเกินไปสำหรับสถานการณ์ง่ายๆ ค่าใช้จ่าย XML |
| SIP | UDP/TCP | รวมกับโครงสร้างพื้นฐาน VoIP และโทรศัพท์ | ซับซ้อน ไม่เป็นเนทีฟสำหรับเบราว์เซอร์ |
| MQTT | TCP | น้ำหนักเบา ทำงานในสภาพแวดล้อม IoT เผยแพร่/สมัครรับ | ต้องใช้ตัวกลาง หน่วงเวลาเพิ่มเติม |
WebSocket เป็นโปรโตคอลที่นิยมที่สุดสำหรับ Signaling Server ในแอปพลิเคชันเว็บ มันให้การสื่อสารแบบฟูลดูเพล็กซ์ ซึ่งสำคัญสำหรับการแลกเปลี่ยนผู้สมัคร SDP และ ICE แบบอะซิงโครนัส และรองรับโดยเบราว์เซอร์สมัยใหม่ทั้งหมดผ่าน WebSocket API การใช้งานฝั่งเซิร์ฟเวอร์ WebSocket มีอยู่ในทุกแพลตฟอร์มยอดนิยม (Node.js, Python, Java, Go) สำหรับแอปพลิเคชันที่มีผู้ใช้หลายล้านคน ใช้โซลูชัน WebSocket ที่ปรับขนาดได้บน Redis Pub/Sub หรือ Kafka เพื่อซิงโครไนซ์ระหว่างอินสแตนซ์ของ Signaling Server
มาดูการใช้งาน Signaling Server อย่างง่ายใน Node.js โดยใช้ไลบรารี ws (WebSocket) และเซิร์ฟเวอร์ HTTP ในตัว เซิร์ฟเวอร์รองรับการลงทะเบียนผู้ใช้ การสร้างห้อง และการถ่ายทอดข้อความระหว่างผู้เข้าร่วม
const WebSocket = require("ws");
const server = new WebSocket.Server({ port: 8080 });
const rooms = new Map();
server.on("connection", (ws) => {
ws.roomId = null;
ws.on("message", (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "join":
handleJoin(ws, msg.roomId);
break;
case "offer":
case "answer":
case "ice-candidate":
relayToPeer(ws, msg);
break;
case "leave":
handleLeave(ws);
break;
}
});
ws.on("close", () => handleLeave(ws));
});
function handleJoin(ws, roomId) {
if (!rooms.has(roomId)) {
rooms.set(roomId, []);
}
const room = rooms.get(roomId);
room.push(ws);
ws.roomId = roomId;
if (room.length === 2) {
room[0].send(JSON.stringify({ type: "peer-joined" }));
room[1].send(JSON.stringify({ type: "peer-joined" }));
}
}
function relayToPeer(sender, msg) {
const room = rooms.get(sender.roomId);
if (!room) return;
room.forEach(peer => {
if (peer !== sender && peer.readyState === WebSocket.OPEN) {
peer.send(JSON.stringify(msg));
}
});
}
function handleLeave(ws) {
if (!ws.roomId) return;
const room = rooms.get(ws.roomId);
if (!room) return;
const idx = room.indexOf(ws);
if (idx !== -1) room.splice(idx, 1);
if (room.length === 0) rooms.delete(ws.roomId);
}
Signaling Server นี้ใช้ฟังก์ชันพื้นฐาน: การเชื่อมต่อกับห้อง การถ่ายทอดข้อความ WebRTC (offer, answer, ice-candidate) ระหว่างเพียร์สองตัวและการจัดการการตัดการเชื่อมต่อ เซิร์ฟเวอร์ใช้ Map เพื่อจัดเก็บห้องกับไคลเอ็นต์ WebSocket ที่เชื่อมต่อ ฟังก์ชัน relayToPeer ส่งข้อความถึงผู้เข้าร่วมทั้งหมดในห้องยกเว้นผู้ส่ง สำหรับการใช้งานจริง คุณจะต้องเพิ่มการตรวจสอบประเภทข้อความ การจัดการข้อผิดพลาดการแยกวิเคราะห์ JSON และกลไก heartbeat สำหรับตรวจจับการเชื่อมต่อที่ขาด
ฝั่งไคลเอ็นต์ Signaling Server ถูกรวมผ่าน WebSocket API ของเบราว์เซอร์ ไคลเอ็นต์สร้างการเชื่อมต่อกับเซิร์ฟเวอร์ ส่งคำขอเข้าร่วมห้อง จากนั้นประมวลผลข้อความ WebRTC ที่เข้ามาโดยส่งต่อไปยัง RTCPeerConnection ผ่าน setRemoteDescription() และ addIceCandidate() โค้ดไคลเอ็นต์ยังส่งผู้สมัคร SDP และ ICE ของตัวเองไปยังเซิร์ฟเวอร์ ซึ่งได้รับจาก RTCPeerConnection ผ่านอีเวนต์ onicecandidate และหลังจากสร้าง offer/answer
Signaling Server ส่งข้อมูลเมตาสองประเภทหลัก: SDP (Session Description Protocol) และผู้สมัคร ICE SDP อธิบายพารามิเตอร์สตรีมสื่อ — ตัวแปลงสัญญาณ อัตราการสุ่มตัวอย่าง จำนวนช่อง ทิศทางการส่ง (sendrecv, sendonly, recvonly, inactive) ผู้สมัคร ICE ประกอบด้วยที่อยู่เครือข่าย (ในเครื่อง ได้จาก STUN รีเลย์จาก TURN) ซึ่งเพียร์สามารถเข้าถึงได้สำหรับการเชื่อมต่อ
SDP นำเสนอในรูปแบบข้อความที่มีส่วนเซสชันและสื่อ ส่วนเซสชันอธิบายพารามิเตอร์ทั่วไป (ID เซสชัน เวอร์ชัน ชื่อ) ในขณะที่ส่วนสื่ออธิบายแต่ละสตรีมสื่อ (เสียง วิดีโอ DataChannel) พร้อมตัวแปลงสัญญาณ พอร์ตและโปรโตคอล ผู้สมัคร ICE ประกอบด้วย foundation (ตัวระบุการจัดกลุ่ม) ลำดับความสำคัญ ที่อยู่ IP พอร์ต ประเภท (host, srflx, relay) และโปรโตคอล (UDP, TCP) ผู้สมัครแต่ละตัวยังรวมถึงแอตทริบิวต์ ufrag (ส่วนชื่อผู้ใช้) ที่เชื่อมโยงกับกระบวนการ ICE เฉพาะ
Trickle ICE เร่งการสร้างการเชื่อมต่อ WebRTC อย่างมีนัยสำคัญ แทนที่จะรอการรวบรวมผู้สมัคร ICE ทั้งหมดให้เสร็จสมบูรณ์ (ซึ่งอาจใช้เวลา 2–10 วินาทีในเครือข่ายที่ซับซ้อน) ผู้สมัครแต่ละตัวจะถูกส่งไปยัง Signaling Server ทันทีหลังจากถูกค้นพบ เพียร์ระยะไกลได้รับผู้สมัครและเริ่มทดสอบการเชื่อมต่อผ่านเฟรมเวิร์ก ICE ทันที ซึ่งช่วยลดเวลาในการสร้างการเชื่อมต่อเหลือ 500–1500 มิลลิวินาทีในกรณีส่วนใหญ่
คำถามที่พบบ่อย
Signaling Server — คือ “ผู้ประสานงาน” ก่อนการโทรมันช่วยให้อุปกรณ์สองเครื่องค้นหากันและตกลงกันว่าพวกเขาจะสื่อสารอย่างไร เมื่ออุปกรณ์ “ทำความรู้จัก” และตกลงกันแล้ว เซิร์ฟเวอร์ก็ไม่จำเป็นอีกต่อไป — พวกเขาสื่อสารโดยตรง
WebRTC ไม่ได้กำหนดโปรโตคอลการส่งสัญญาณ เพื่อให้นักพัฒนาสามารถเลือกการขนส่งที่เหมาะสมที่สุด เบราว์เซอร์ไม่มีกลไกในตัวสำหรับการค้นหาผู้ใช้อื่น — งานนี้ดำเนินการโดย Signaling Server มันทำหน้าที่เป็น “บุรุษไปรษณีย์” ส่งคำเชิญและการตั้งค่าการเชื่อมต่อระหว่างผู้เข้าร่วมการโทร
WebSocket — เป็นตัวเลือกที่เหมาะสมที่สุดสำหรับแอปพลิเคชันเว็บส่วนใหญ่: ฟูลดูเพล็กซ์ รองรับโดยเบราว์เซอร์แบบเนทีฟ และใช้งานง่าย สำหรับการรวมกับโครงสร้างพื้นฐาน VoIP ที่มีอยู่ เลือก SIP สำหรับแอปพลิเคชันแชทที่มีฟีเจอร์มากมาย ใช้ XMPP สำหรับสถานการณ์ IoT ใช้ MQTT
สำหรับการปรับขนาด Signaling Server ให้ใช้การปรับขนาดแนวนอนด้วยการซิงโครไนซ์ผ่าน Redis Pub/Sub หรือ Kafka แต่ละอินสแตนซ์ของเซิร์ฟเวอร์จัดการส่วนแบ่งการเชื่อมต่อ WebSocket ของตนเอง และใช้บัสข้อมูลร่วมกันสำหรับการกำหนดเส้นทางข้อความระหว่างเซิร์ฟเวอร์ วิธีการนี้ช่วยให้จัดการเซสชันการส่งสัญญาณพร้อมกันนับล้านรายการ
Signaling Server มีความสำคัญเฉพาะในช่วงสร้างการเชื่อมต่อเท่านั้น หากเซิร์ฟเวอร์ไม่พร้อมใช้งานชั่วคราว การโทร WebRTC ที่ใช้งานอยู่ยังคงดำเนินต่อไป — ทราฟฟิกสื่อไหลโดยตรงระหว่างเพียร์ ปัญหาเกิดขึ้นเฉพาะเมื่อพยายามสร้างการเชื่อมต่อใหม่เท่านั้น เพื่อความน่าเชื่อถือ ให้ใช้การคลัสเตอร์เซิร์ฟเวอร์และช่องทางส่งสัญญาณสำรอง
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ