แนะนำ WebSockets - นำซ็อกเก็ตขึ้นไปบนเว็บ

ปัญหา: การเชื่อมต่อแบบไคลเอ็นต์-เซิร์ฟเวอร์และเซิร์ฟเวอร์-ไคลเอ็นต์ที่ใช้เวลาในการตอบสนองต่ำ

เว็บส่วนใหญ่สร้างขึ้นด้วยรูปแบบคำขอ/การตอบกลับที่เรียกกันว่า HTTP ไคลเอ็นต์โหลดหน้าเว็บขึ้นมา จากนั้นไม่มีอะไรเกิดขึ้นจนกว่าผู้ใช้จะคลิกไปยังหน้าถัดไป ประมาณปี 2005 AJAX ได้เริ่มทำให้เว็บมีบรรยากาศที่ลื่นไหลมากขึ้น อย่างไรก็ตาม ไคลเอ็นต์จะเป็นผู้ควบคุมการสื่อสาร HTTP ทั้งหมด ซึ่งจำเป็นต้องมีการโต้ตอบของผู้ใช้หรือการสำรวจเป็นระยะๆ เพื่อโหลดข้อมูลใหม่จากเซิร์ฟเวอร์

เทคโนโลยีที่ทำให้เซิร์ฟเวอร์สามารถส่งข้อมูลไปยังไคลเอ็นต์ขณะที่ทราบว่ามีข้อมูลใหม่รออยู่ระยะหนึ่งแล้ว โดยจะใช้ชื่ออย่างเช่น "Push" หรือ "Comet" การแฮ็กที่พบเห็นได้บ่อยที่สุดอย่างหนึ่งในการสร้างภาพลวงตาว่าการเชื่อมต่อนั้นเริ่มมาจากเซิร์ฟเวอร์เรียกว่า การหยั่งสัญญาณเป็นระยะเวลานาน เมื่อใช้แบบสำรวจที่ใช้เวลานาน ไคลเอ็นต์จะเปิดการเชื่อมต่อ HTTP ไปยังเซิร์ฟเวอร์ ซึ่งจะเปิดไว้จนกว่าจะมีการส่งการตอบกลับ เมื่อใดก็ตามที่เซิร์ฟเวอร์มีข้อมูลใหม่จริงๆ เซิร์ฟเวอร์จะส่งการตอบกลับ (เทคนิคอื่นๆ เกี่ยวข้องกับคำขอ Flash, หลายส่วน XHR และเรียกว่า htmlfiles) แบบสำรวจที่ใช้เวลานานและเทคนิคอื่นๆ ใช้ได้ผลค่อนข้างดี คุณใช้แอปพลิเคชันเหล่านี้ทุกวันในแอปพลิเคชันต่างๆ เช่น แชท GMail

อย่างไรก็ตาม วิธีแก้ปัญหาเบื้องต้นทั้งหมดนี้จะต้องมีปัญหาเดียวกัน นั่นก็คือปัญหาที่มีโอเวอร์เฮดของ HTTP ซึ่งไม่เหมาะสำหรับแอปพลิเคชันที่เวลาในการตอบสนองต่ำ ลองนึกถึงเกมยิงมุมมองผู้เล่นแบบผู้เล่นหลายคนในเบราว์เซอร์หรือเกมออนไลน์อื่นๆ ที่มีคอมโพเนนต์แบบเรียลไทม์

แนะนำ WebSocket: นำซ็อกเก็ตขึ้นไปบนเว็บ

ข้อกำหนด WebSocket กำหนด API ที่สร้างการเชื่อมต่อ "ซ็อกเก็ต" ระหว่างเว็บเบราว์เซอร์กับเซิร์ฟเวอร์ กล่าวง่ายๆ ก็คือ มีการเชื่อมต่อระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์อย่างต่อเนื่อง และทั้ง 2 ฝ่ายสามารถเริ่มส่งข้อมูลได้ทุกเมื่อ

เริ่มต้นใช้งาน

คุณสามารถเปิดการเชื่อมต่อ WebSocket ได้ง่ายๆ โดยเรียกตัวสร้าง WebSocket ดังนี้

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

สังเกต ws: นี่คือสคีมา URL ใหม่สำหรับการเชื่อมต่อ WebSocket นอกจากนี้ ยังมี wss: สำหรับการเชื่อมต่อ WebSocket ที่ปลอดภัยเช่นเดียวกับที่ใช้ https: สำหรับการเชื่อมต่อ HTTP ที่ปลอดภัย

การแนบตัวแฮนเดิลเหตุการณ์บางอย่างลงในการเชื่อมต่อโดยทันทีจะช่วยให้คุณรู้เมื่อมีการเปิดการเชื่อมต่อ ได้รับข้อความขาเข้า หรือมีข้อผิดพลาด

อาร์กิวเมนต์ที่ 2 ยอมรับโปรโตคอลย่อยที่ไม่บังคับ ซึ่งอาจเป็นสตริงหรืออาร์เรย์ของสตริงก็ได้ แต่ละสตริงควรแทนชื่อโปรโตคอลย่อยและเซิร์ฟเวอร์ยอมรับโปรโตคอลย่อยที่ส่งเพียง 1 รายการในอาร์เรย์ โปรโตคอลย่อยที่ยอมรับจะกำหนดได้โดยการเข้าถึงพร็อพเพอร์ตี้ protocol ของออบเจ็กต์ WebSocket

ชื่อโปรโตคอลย่อยต้องเป็นหนึ่งในชื่อโปรโตคอลย่อยที่จดทะเบียนในองค์กรจัดการข้อมูลโดเมน IANA ปัจจุบันมีชื่อโปรโตคอลย่อย (สบู่) เพียงชื่อเดียวที่จดทะเบียนตั้งแต่เดือนกุมภาพันธ์ 2012

// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};

การสื่อสารกับเซิร์ฟเวอร์

ทันทีที่เชื่อมต่อกับเซิร์ฟเวอร์ (เมื่อเหตุการณ์ open เริ่มทํางาน) เราจะเริ่มส่งข้อมูลไปยังเซิร์ฟเวอร์โดยใช้เมธอด send('your message') ในออบเจ็กต์การเชื่อมต่อได้ เครื่องมือดังกล่าวเคยรองรับเฉพาะสตริงเท่านั้น แต่ในข้อมูลจำเพาะล่าสุด ตอนนี้สามารถส่งข้อความไบนารีได้ด้วย หากต้องการส่งข้อมูลไบนารี คุณจะใช้ออบเจ็กต์ Blob หรือ ArrayBuffer ก็ได้

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

และเช่นเดียวกัน เซิร์ฟเวอร์อาจส่งข้อความถึงเราได้ทุกเมื่อ เมื่อเกิดปัญหานี้ขึ้น โค้ดเรียกกลับ onmessage จะเริ่มทำงาน โค้ดเรียกกลับจะได้รับออบเจ็กต์เหตุการณ์ และเข้าถึงข้อความจริงได้ผ่านพร็อพเพอร์ตี้ data

WebSocket ยังสามารถรับข้อความไบนารีในข้อกำหนดล่าสุด รับเฟรมไบนารีในรูปแบบ Blob หรือ ArrayBuffer หากต้องการระบุรูปแบบของไบนารีที่ได้รับ ให้ตั้งค่าพร็อพเพอร์ตี้ไบนารีของออบเจ็กต์ WebSocket เป็น "blob" หรือ "arraybuffer" รูปแบบเริ่มต้นคือ "blob" (คุณไม่จำเป็นต้องจัดเรียงพารามิเตอร์ BinaryType ใหม่เมื่อส่ง)

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};

อีกหนึ่งฟีเจอร์ที่เพิ่มเข้ามาใหม่ของ WebSocket คือส่วนขยาย เมื่อใช้ส่วนขยาย คุณจะสามารถส่งเฟรมที่บีบอัด, multiplexed ฯลฯ คุณสามารถค้นหาส่วนขยายที่เซิร์ฟเวอร์ยอมรับโดยตรวจสอบพร็อพเพอร์ตี้ส่วนขยายของออบเจ็กต์ WebSocket หลังเหตุการณ์เปิด ยังไม่มีข้อกำหนดของส่วนขยายที่เผยแพร่อย่างเป็นทางการตั้งแต่เดือนกุมภาพันธ์ 2012

// Determining accepted extensions
console.log(connection.extensions);

การสื่อสารข้ามต้นทาง

การเป็นโปรโตคอลสมัยใหม่ช่วยให้การสื่อสารแบบข้ามต้นทางอยู่ใน WebSocket โดยตรง แม้ว่าคุณควรตรวจสอบว่าการสื่อสารกับลูกค้าและเซิร์ฟเวอร์ที่คุณเชื่อถือเท่านั้น WebSocket จะทำให้สามารถใช้การสื่อสารระหว่างบุคคลในโดเมนใดก็ได้ เซิร์ฟเวอร์จะตัดสินใจว่าจะให้บริการสำหรับไคลเอ็นต์ทั้งหมด หรือเฉพาะที่ที่อยู่บนโดเมนที่กำหนดไว้เป็นอย่างดีเท่านั้น

พร็อกซีเซิร์ฟเวอร์

เทคโนโลยีใหม่ๆ มาพร้อมปัญหาชุดใหม่ ในกรณีของ WebSocket คือความเข้ากันได้กับพร็อกซีเซิร์ฟเวอร์ที่เป็นสื่อกลางในการเชื่อมต่อ HTTP ในเครือข่ายบริษัทส่วนใหญ่ โปรโตคอล WebSocket ใช้ระบบอัปเกรด HTTP (ซึ่งปกติใช้สำหรับ HTTP/SSL) เพื่อ "อัปเกรด" การเชื่อมต่อ HTTP เป็นการเชื่อมต่อ WebSocket บางพร็อกซีเซิร์ฟเวอร์ไม่ชอบฟีเจอร์นี้และจะยกเลิกการเชื่อมต่อ ดังนั้น แม้ไคลเอ็นต์ที่ระบุจะใช้โปรโตคอล WebSocket ก็อาจไม่สามารถทำการเชื่อมต่อได้ ทำให้ส่วนถัดไปมีความสำคัญมากยิ่งขึ้น :)

ใช้ WebSockets วันนี้

WebSocket ยังเป็นเทคโนโลยีรุ่นใหม่และยังไม่พร้อมใช้งานอย่างเต็มรูปแบบกับทุกเบราว์เซอร์ อย่างไรก็ตาม ในปัจจุบันคุณสามารถใช้ WebSocket กับไลบรารีที่ใช้รายการสำรองแบบใดแบบหนึ่งที่กล่าวถึงข้างต้นเมื่อใดก็ตามที่ WebSocket ไม่พร้อมใช้งาน ไลบรารีที่ได้รับความนิยมมากในโดเมนนี้คือ socket.io ซึ่งมาพร้อมไคลเอ็นต์และเซิร์ฟเวอร์ที่ใช้โปรโตคอล รวมถึงใช้โปรโตคอลสำรอง (socket.io ยังไม่รองรับการรับส่งข้อความไบนารีตั้งแต่เดือนกุมภาพันธ์ 2012) นอกจากนี้ ยังมีโซลูชันเชิงพาณิชย์ เช่น PusherApp ที่ผสานรวมเข้ากับสภาพแวดล้อมของเว็บได้ง่ายๆ ด้วยการให้บริการ HTTP API เพื่อส่งข้อความ WebSocket ไปยังไคลเอ็นต์ เนื่องจากมีคำขอ HTTP เพิ่มเติม จะมีโอเวอร์เฮดเพิ่มเติมอยู่เสมอเมื่อเทียบกับ WebSocket เพียงอย่างเดียว

ฝั่งเซิร์ฟเวอร์

การใช้ WebSocket จะสร้างรูปแบบการใช้งานใหม่ทั้งหมดสำหรับแอปพลิเคชันฝั่งเซิร์ฟเวอร์ แม้ว่าสแต็กเซิร์ฟเวอร์แบบดั้งเดิม เช่น LAMP จะได้รับการออกแบบมาตามรอบคำขอ/การตอบกลับ HTTP แต่สแต็กเซิร์ฟเวอร์มักไม่รับมือกับการเชื่อมต่อ WebSocket แบบเปิดจำนวนมาก การเปิดการเชื่อมต่อจำนวนมากไว้พร้อมกันจำเป็นต้องใช้สถาปัตยกรรมที่มีการเกิดขึ้นพร้อมกันสูงโดยมีค่าใช้จ่ายต่ำ สถาปัตยกรรมดังกล่าวมักออกแบบจากการแยกชุดข้อความ (Threading) หรือเรียกว่า IO แบบไม่บล็อก

การใช้งานฝั่งเซิร์ฟเวอร์

เวอร์ชันของโปรโตคอล

ตอนนี้โปรโตคอลสาย (แฮนด์เชคและการโอนข้อมูลระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์) สำหรับ WebSocket เปลี่ยนเป็น RFC6455 แล้ว Chrome ล่าสุดและ Chrome สำหรับ Android เข้ากันได้กับ RFC6455 รวมถึงการรับส่งข้อความไบนารี นอกจากนี้ Firefox จะสามารถใช้งานใน Internet Explorer เวอร์ชัน 11 ได้บนเวอร์ชัน 10 คุณยังสามารถใช้โปรโตคอลเวอร์ชันเก่าได้ แต่เราไม่แนะนําให้ใช้เนื่องจากเป็นที่ทราบว่ามีช่องโหว่ หากคุณใช้เซิร์ฟเวอร์สำหรับโปรโตคอล WebSocket เวอร์ชันเก่า เราขอแนะนำให้คุณอัปเกรดเป็นเวอร์ชันล่าสุด

Use Case

ใช้ WebSocket เมื่อใดก็ตามที่คุณต้องการเวลาในการตอบสนองที่ต่ำอย่างแท้จริง โดยใช้การเชื่อมต่อแบบเกือบเรียลไทม์ระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ โปรดทราบว่าการดำเนินการนี้อาจเกี่ยวข้องกับการทบทวนเกี่ยวกับวิธีสร้างแอปพลิเคชันฝั่งเซิร์ฟเวอร์โดยมุ่งเน้นไปที่เทคโนโลยีใหม่ เช่น คิวกิจกรรม ตัวอย่างกรณีการใช้งานมีดังนี้

  • เกมออนไลน์แบบผู้เล่นหลายคน
  • แอปพลิเคชันแชท
  • ทิกเกอร์การถ่ายทอดสดกีฬา
  • การอัปเดตสตรีมโซเชียลแบบเรียลไทม์

เดโม

รายการอ้างอิง