การส่งข้อมูลระหว่างเบราว์เซอร์ 2 ตัวเพื่อการสื่อสาร การเล่นเกม หรือการโอนไฟล์อาจเป็นกระบวนการที่ค่อนข้างซับซ้อน ซึ่งต้องตั้งค่าและชำระเงินสำหรับเซิร์ฟเวอร์เพื่อส่งต่อข้อมูล และอาจต้องปรับขนาดเซิร์ฟเวอร์นี้ไปยังศูนย์ข้อมูลหลายแห่ง ในสถานการณ์นี้ อาจเกิดความหน่วงสูงและรักษาข้อมูลให้เป็นส่วนตัวได้ยาก
ปัญหาเหล่านี้สามารถบรรเทาได้โดยใช้ RTCDataChannel
API ของ WebRTC เพื่อโอนข้อมูลจากเพียร์หนึ่งไปยังอีกเพียร์หนึ่งโดยตรง บทความนี้ครอบคลุมพื้นฐานของวิธีตั้งค่าและใช้ช่องทางข้อมูล รวมถึงกรณีการใช้งานที่พบบ่อยบนเว็บในปัจจุบัน
ทำไมต้องมีช่องทางข้อมูลอื่น
เรามี WebSocket, AJAX และ Server Sent Events ทำไมเราจึงต้องมีช่องทางการสื่อสารอื่น WebSocket เป็นแบบ 2 ทิศทาง แต่เทคโนโลยีทั้งหมดนี้ออกแบบมาเพื่อการสื่อสารไปยังหรือจากเซิร์ฟเวอร์
RTCDataChannel
ใช้วิธีการที่แตกต่างออกไป ดังนี้
- โดยจะทำงานร่วมกับ
RTCPeerConnection
API ซึ่งช่วยให้เชื่อมต่อแบบเพียร์ทูเพียร์ได้ ซึ่งจะช่วยลดเวลาในการตอบสนองได้ เนื่องจากไม่มีเซิร์ฟเวอร์ตัวกลางและมี "การข้าม" น้อยลง RTCDataChannel
ใช้ Stream Control Transmission Protocol (SCTP) ซึ่งช่วยให้กำหนดค่าการจัดส่งตามความหมายได้ เช่น การจัดส่งแบบไม่เรียงตามลำดับและการกำหนดค่าการส่งซ้ำ
RTCDataChannel
พร้อมให้บริการแล้วโดยรองรับ SCTP บนเดสก์ท็อปและ Android ใน Google Chrome, Opera และ Firefox
ข้อควรระวัง: การส่งสัญญาณ, STUN และ TURN
WebRTC ช่วยให้การสื่อสารแบบเพียร์ทูเพียร์เป็นไปได้ แต่ก็ยังต้องใช้เซิร์ฟเวอร์สำหรับการส่งสัญญาณเพื่อแลกเปลี่ยนสื่อและข้อมูลเมตาของเครือข่ายเพื่อเริ่มต้นการเชื่อมต่อเพียร์
WebRTC จัดการ NAT และไฟร์วอลล์ด้วยสิ่งต่อไปนี้
- กรอบ ICE เพื่อสร้างเส้นทางเครือข่ายที่ดีที่สุดเท่าที่จะเป็นไปได้ระหว่างเพียร์
- เซิร์ฟเวอร์ STUN เพื่อตรวจสอบ IP และพอร์ตที่เข้าถึงได้แบบสาธารณะสำหรับแต่ละเพียร์
- เซิร์ฟเวอร์ TURN หากการเชื่อมต่อโดยตรงล้มเหลวและต้องมีการส่งต่อข้อมูล
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่ WebRTC ทำงานร่วมกับเซิร์ฟเวอร์สำหรับการส่งสัญญาณและการเชื่อมต่อเครือข่ายได้ที่ WebRTC ในโลกแห่งความเป็นจริง: STUN, TURN และการส่งสัญญาณ
ความสามารถ
RTCDataChannel
API รองรับชุดประเภทข้อมูลที่ยืดหยุ่น API นี้ออกแบบมาให้เลียนแบบ WebSocket อย่างแม่นยำ และ RTCDataChannel
รองรับทั้งสตริงและไบนารีบางประเภทใน JavaScript เช่น Blob, ArrayBuffer และ ArrayBufferView ประเภทเหล่านี้อาจมีประโยชน์เมื่อทำงานกับการโอนไฟล์และการเล่นเกมแบบผู้เล่นหลายคน
RTCDataChannel
สามารถทำงานในโหมดที่ไม่น่าเชื่อถือและไม่มีการเรียงลำดับ (คล้ายกับ User Datagram Protocol หรือ UDP), โหมดที่น่าเชื่อถือและมีการเรียงลำดับ (คล้ายกับ Transmission Control Protocol หรือ TCP) และโหมดที่น่าเชื่อถือบางส่วน
- โหมดที่เชื่อถือได้และเรียงตามลำดับจะรับประกันการส่งข้อความและลำดับการนำส่ง ซึ่งจะเพิ่มค่าใช้จ่ายเพิ่มเติม จึงอาจทำให้โหมดนี้ช้าลง
- โหมดที่ไม่น่าเชื่อถือและไม่มีการเรียงลำดับไม่รับประกันว่าทุกข้อความจะไปถึงอีกฝั่งหรือลำดับที่ข้อความไปถึง ซึ่งจะช่วยลดค่าใช้จ่าย ทำให้โหมดนี้ทำงานได้เร็วขึ้นมาก
- โหมดเชื่อถือได้บางส่วนรับประกันการส่งข้อความภายใต้เงื่อนไขที่เฉพาะเจาะจง เช่น การหมดเวลาการส่งซ้ำหรือจำนวนการส่งซ้ำสูงสุด นอกจากนี้ คุณยังกำหนดค่าการเรียงลำดับข้อความได้ด้วย
ประสิทธิภาพของ 2 โหมดแรกจะใกล้เคียงกันเมื่อไม่มีแพ็กเก็ตสูญหาย อย่างไรก็ตาม ในโหมดที่เชื่อถือได้และเรียงตามลำดับ แพ็กเก็ตที่สูญหายจะทำให้แพ็กเก็ตอื่นๆ ถูกบล็อกอยู่ข้างหลัง และแพ็กเก็ตที่สูญหายอาจล้าสมัยเมื่อมีการส่งซ้ำและมาถึง แน่นอนว่าคุณใช้ช่องข้อมูลหลายช่องภายในแอปเดียวกันได้ โดยแต่ละช่องจะมีซีแมนติกที่เชื่อถือได้หรือไม่ก็ได้
ตารางต่อไปนี้จาก High Performance Browser Networking โดย Ilya Grigorik จะเป็นประโยชน์
TCP | UDP | SCTP | |
ความน่าเชื่อถือ | เชื่อถือได้ | ไม่น่าเชื่อถือ | กำหนดค่าได้ |
บริการจัดส่ง | ตามลำดับ | ไม่เรียงลำดับ | กำหนดค่าได้ |
ชุดเกียร์ | มุ่งเน้นไบต์ | เน้นข้อความ | เน้นข้อความ |
การควบคุมโฟลว์ | ใช่ | ไม่ใช่ | ใช่ |
การควบคุมความแออัด | ใช่ | ไม่ใช่ | ใช่ |
จากนั้น คุณจะได้เรียนรู้วิธีกำหนดค่า RTCDataChannel
เพื่อใช้โหมดที่เชื่อถือได้และเรียงตามลำดับ หรือโหมดที่ไม่น่าเชื่อถือและไม่เรียงตามลำดับ
การกำหนดค่าแชแนลข้อมูล
RTCDataChannel
มีการสาธิตแบบง่ายๆ หลายรายการทางออนไลน์ ดังนี้
ในตัวอย่างเหล่านี้ เบราว์เซอร์จะสร้างการเชื่อมต่อเพียร์กับตัวเอง จากนั้นสร้างแชแนลข้อมูลและส่งข้อความผ่านการเชื่อมต่อเพียร์ จากนั้นจะสร้างช่องข้อมูลและส่งข้อความผ่านการเชื่อมต่อเพียร์ สุดท้าย ข้อความของคุณจะปรากฏในช่องที่อีกด้านหนึ่งของหน้า
โค้ดสำหรับเริ่มต้นใช้งานนี้สั้นๆ ดังนี้
const peerConnection = new RTCPeerConnection();
// Establish your peer connection using your signaling channel here
const dataChannel =
peerConnection.createDataChannel("myLabel", dataChannelOptions);
dataChannel.onerror = (error) => {
console.log("Data Channel Error:", error);
};
dataChannel.onmessage = (event) => {
console.log("Got Data Channel Message:", event.data);
};
dataChannel.onopen = () => {
dataChannel.send("Hello World!");
};
dataChannel.onclose = () => {
console.log("The Data Channel is Closed");
};
ระบบจะสร้างออบเจ็กต์ dataChannel
จากการเชื่อมต่อเพียร์ที่สร้างไว้แล้ว โดยคุณจะสร้างได้ก่อนหรือหลังการส่งสัญญาณ จากนั้นคุณจะส่งป้ายกำกับเพื่อแยกแยะช่องนี้จากช่องอื่นๆ และชุดการตั้งค่าการกำหนดค่าที่ไม่บังคับได้
const dataChannelOptions = {
ordered: false, // do not guarantee order
maxPacketLifeTime: 3000, // in milliseconds
};
นอกจากนี้ คุณยังเพิ่มmaxRetransmits
ตัวเลือก (จำนวนครั้งที่จะลองก่อนล้มเหลว) ได้ด้วย แต่จะระบุได้เพียง maxRetransmits หรือ maxPacketLifeTime เท่านั้น ไม่ใช่ทั้ง 2 อย่าง สำหรับความหมายของ UDP ให้ตั้งค่า maxRetransmits
เป็น 0
และ ordered
เป็น false
ดูข้อมูลเพิ่มเติมได้ที่ RFC ของ IETF เหล่านี้ Stream Control Transmission Protocol และ Stream Control Transmission Protocol Partial Reliability Extension
ordered
: หากช่องข้อมูลควรรับประกันลำดับหรือไม่maxPacketLifeTime
: เวลาสูงสุดในการลองส่งข้อความที่ไม่สำเร็จอีกครั้งmaxRetransmits
: จำนวนครั้งสูงสุดในการลองส่งข้อความที่ไม่สำเร็จอีกครั้งprotocol
: อนุญาตให้ใช้โปรโตคอลย่อย ซึ่งให้ข้อมูลเมตาแก่แอปnegotiated
: หากตั้งค่าเป็น true จะนำการตั้งค่าช่องข้อมูลโดยอัตโนมัติในเพียร์อีกรายออก เพื่อให้คุณสร้างช่องข้อมูลด้วยรหัสเดียวกันในอีกฝั่งได้ด้วยตนเองid
: ช่วยให้คุณระบุรหัสของช่องเองได้ ซึ่งจะใช้ร่วมกับnegotiated
ที่ตั้งค่าเป็นtrue
ได้เท่านั้น)
ตัวเลือกที่คนส่วนใหญ่ต้องใช้มีเพียง 3 ตัวเลือกแรก ได้แก่ ordered
, maxPacketLifeTime
และ maxRetransmits
เมื่อใช้ SCTP (ปัจจุบันเบราว์เซอร์ทั้งหมดที่รองรับ WebRTC ใช้ SCTP) ค่าเริ่มต้นของเชื่อถือได้และเรียงลำดับจะเป็นจริง การใช้แบบไม่น่าเชื่อถือและไม่มีการเรียงลำดับจะสมเหตุสมผลหากคุณต้องการควบคุมอย่างเต็มที่จากเลเยอร์แอป แต่ในกรณีส่วนใหญ่ ความน่าเชื่อถือบางส่วนก็มีประโยชน์
โปรดทราบว่าเช่นเดียวกับ WebSocket RTCDataChannel
จะทริกเกอร์เหตุการณ์เมื่อมีการสร้าง ปิด หรือเกิดข้อผิดพลาดในการเชื่อมต่อ และเมื่อได้รับข้อความจากเพียร์อื่น
เทรนด์หรือชาเลนจ์นี้ปลอดภัยไหม
คอมโพเนนต์ WebRTC ทั้งหมดต้องมีการเข้ารหัส RTCDataChannel
จะรักษาความปลอดภัยข้อมูลทั้งหมดด้วย Datagram Transport Layer Security (DTLS) DTLS เป็นอนุพันธ์ของ SSL ซึ่งหมายความว่าข้อมูลของคุณจะปลอดภัยเหมือนกับการใช้การเชื่อมต่อมาตรฐานที่ใช้ SSL DTLS ได้รับการกำหนดมาตรฐานและสร้างขึ้นในเบราว์เซอร์ทั้งหมดที่รองรับ WebRTC ดูข้อมูลเพิ่มเติมได้ที่ Wireshark wiki
เปลี่ยนวิธีคิดเกี่ยวกับข้อมูล
การจัดการข้อมูลจำนวนมากอาจเป็นปัญหาใน JavaScript ดังที่นักพัฒนาแอป Sharefest ได้ชี้ให้เห็น การดำเนินการนี้ต้องพิจารณาข้อมูลในรูปแบบใหม่ หากคุณกำลังโอนไฟล์ที่มีขนาดใหญ่กว่าปริมาณหน่วยความจำที่คุณมีอยู่ คุณจะต้องคิดหาวิธีใหม่ๆ ในการบันทึกข้อมูลนี้ เทคโนโลยีต่างๆ เช่น FileSystem API จึงมีบทบาทในส่วนนี้ ดังที่คุณจะเห็นต่อไป
สร้างแอปแชร์ไฟล์
ตอนนี้คุณสร้างเว็บแอปที่แชร์ไฟล์ในเบราว์เซอร์ได้แล้วด้วย RTCDataChannel
การสร้างบน RTCDataChannel
หมายความว่าข้อมูลไฟล์ที่โอนจะได้รับการเข้ารหัสและจะไม่แตะต้องเซิร์ฟเวอร์ของผู้ให้บริการแอป ฟังก์ชันนี้เมื่อรวมกับความเป็นไปได้ในการเชื่อมต่อกับไคลเอ็นต์หลายรายเพื่อการแชร์ที่เร็วขึ้น ทำให้การแชร์ไฟล์ผ่าน WebRTC เป็นตัวเลือกที่น่าสนใจสำหรับเว็บ
คุณต้องทำตามขั้นตอนต่อไปนี้เพื่อให้การโอนสำเร็จ
- อ่านไฟล์ใน JavaScript โดยใช้ File API
- สร้างการเชื่อมต่อแบบเพียร์ระหว่างไคลเอ็นต์ด้วย
RTCPeerConnection
- สร้างช่องข้อมูลระหว่างไคลเอ็นต์ด้วย
RTCDataChannel
มีหลายประเด็นที่ต้องพิจารณาเมื่อพยายามส่งไฟล์ผ่าน RTCDataChannel
ดังนี้
- ขนาดไฟล์: หากขนาดไฟล์เล็กพอสมควรและจัดเก็บและโหลดเป็น Blob เดียวได้ คุณจะโหลดลงในหน่วยความจำโดยใช้ File API แล้วส่งไฟล์ผ่านช่องทางที่เชื่อถือได้ตามเดิมได้ (โปรดทราบว่าเบราว์เซอร์กำหนดขีดจำกัดขนาดการโอนสูงสุด) แต่เมื่อไฟล์มีขนาดใหญ่ขึ้น การจัดการก็จะยากขึ้น เมื่อต้องใช้กลไกการแบ่งไฟล์ ระบบจะโหลดและส่งไฟล์ที่แบ่งเป็นส่วนๆ ไปยังเพียร์รายอื่นพร้อมกับ
chunkID
ข้อมูลเมตาเพื่อให้เพียร์ดังกล่าวจดจำได้ โปรดทราบว่าในกรณีนี้ คุณจะต้องบันทึกก้อนข้อมูลลงในพื้นที่เก็บข้อมูลแบบออฟไลน์ก่อน (เช่น ใช้ FileSystem API) และบันทึกลงในดิสก์ของผู้ใช้เฉพาะเมื่อคุณมีไฟล์ครบถ้วนแล้วเท่านั้น - ขนาดก้อนข้อมูล: นี่คือ "หน่วย" ข้อมูลที่เล็กที่สุดสำหรับแอปของคุณ คุณต้องแบ่งข้อมูลออกเป็นก้อนเนื่องจากปัจจุบันมีขีดจำกัดขนาดการส่ง (แม้ว่าปัญหานี้จะได้รับการแก้ไขในช่องทางข้อมูลเวอร์ชันในอนาคต) คำแนะนำปัจจุบันสำหรับขนาดก้อนข้อมูลสูงสุดคือ 64 KiB
เมื่อโอนไฟล์ไปยังอีกฝั่งจนเสร็จสมบูรณ์แล้ว คุณจะดาวน์โหลดไฟล์ได้โดยใช้แท็ก Anchor ดังนี้
function saveFile(blob) {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'File Name';
link.click();
};
แอปแชร์ไฟล์เหล่านี้ใน PubShare และ GitHub ใช้เทคนิคนี้ ทั้ง 2 อย่างเป็นโอเพนซอร์สและเป็นรากฐานที่ดีสำหรับแอปแชร์ไฟล์ที่อิงตาม RTCDataChannel
แล้วคุณจะทำอะไรได้บ้าง
RTCDataChannel
เปิดโอกาสให้สร้างแอปในรูปแบบใหม่สำหรับการแชร์ไฟล์ เกมแบบผู้เล่นหลายคน และการนำส่งเนื้อหา
- การแชร์ไฟล์แบบเพียร์ทูเพียร์ตามที่อธิบายไว้ก่อนหน้านี้
- การเล่นเกมแบบผู้เล่นหลายคนร่วมกับเทคโนโลยีอื่นๆ เช่น WebGL ดังที่เห็นใน BananaBread ของ Mozilla
- PeerCDN กำลังปรับปรุงการแสดงเนื้อหาใหม่ ซึ่งเป็นเฟรมเวิร์กที่แสดงชิ้นงานบนเว็บผ่านการสื่อสารข้อมูลแบบเพียร์ทูเพียร์
เปลี่ยนวิธีสร้างแอป
ตอนนี้คุณสามารถให้บริการแอปที่น่าสนใจยิ่งขึ้นได้ด้วยการใช้การเชื่อมต่อที่มีประสิทธิภาพสูงและมีความหน่วงต่ำผ่าน RTCDataChannel
เฟรมเวิร์ก เช่น PeerJS และ PubNub WebRTC SDK ทำให้RTCDataChannel
ใช้งานได้ง่ายขึ้น และตอนนี้ API ก็รองรับแพลตฟอร์มต่างๆ อย่างกว้างขวาง
การมาถึงของ RTCDataChannel
สามารถเปลี่ยนวิธีที่คุณคิดเกี่ยวกับการโอนข้อมูลในเบราว์เซอร์ได้