อ่าน 16 นาที
เว็บซ็อกเก็ต
WebSocket เป็น โปรโตคอลการสื่อสาร คอมพิวเตอร์ ที่ให้ ช่องทางการสื่อสาร แบบสองทิศทาง ผ่านการเชื่อมต่อ Transmission Control Protocol (TCP) เดียว โปรโตคอลนี้ได้รับการกำหนดมาตรฐานโดย...
เว็บซ็อกเก็ต
โลโก้ WebSocket | |
| มาตรฐานสากล |
|
|---|---|
| พัฒนาโดย | |
| แนะนำ | ธันวาคม 2554 |
| อุตสาหกรรม | วิทยาการคอมพิวเตอร์ |
| ประเภทตัวเชื่อมต่อ | ทีพีซีพี |
WebSocketเป็นโปรโตคอลการสื่อสาร คอมพิวเตอร์ ที่ให้ ช่องทางการสื่อสาร แบบสองทิศทาง ผ่านการเชื่อมต่อ Transmission Control Protocol (TCP) เดียว โปรโตคอลนี้ได้รับการกำหนดมาตรฐานโดย IETFเป็นRFC 6455 ในปี 2011 ข้อกำหนดปัจจุบันที่อนุญาตให้เว็บแอปพลิ เคชันใช้โปรโตคอลนี้เรียกว่าWebSockets [ 1 ]เป็นมาตรฐานที่มีการพัฒนาอย่างต่อเนื่องโดยWHATWGและเป็นผู้สืบทอดต่อจากWebSocket APIจากW3C [ 2 ]
WebSocket แตกต่างจากHTTPที่ใช้ในการให้บริการเว็บเพจส่วนใหญ่ แม้ว่าจะแตกต่างกัน แต่RFC 6455ระบุว่า WebSocket "ได้รับการออกแบบให้ทำงานบนพอร์ต HTTP 443 และ 80 รวมถึงรองรับพร็อกซีและตัวกลาง HTTP" ทำให้โปรโตคอล WebSocket เข้ากันได้กับ HTTP เพื่อให้เข้ากันได้การจับมือ ของ WebSocket จะใช้ส่วนหัว HTTP Upgrade [ 3 ]เพื่อเปลี่ยนจากโปรโตคอล HTTP เป็นโปรโตคอล WebSocket
โปรโตคอล WebSocket ช่วยให้สามารถ สื่อสาร แบบฟูลดูเพล็กซ์ระหว่างเว็บเบราว์เซอร์ (หรือ แอปพลิเค ชันไคลเอ็นต์ อื่นๆ ) กับเว็บเซิร์ฟเวอร์ได้ โดยมีค่าใช้จ่ายน้อยกว่าทางเลือกแบบฮาล์ฟดูเพล็กซ์ เช่นการสำรวจ HTTP ซึ่งอำนวยความสะดวกในการถ่ายโอนข้อมูลแบบเรียลไทม์จากและไปยังเซิร์ฟเวอร์ สิ่งนี้เกิดขึ้นได้โดยการจัดเตรียมวิธีการมาตรฐานสำหรับเซิร์ฟเวอร์ในการส่งเนื้อหาไปยังไคลเอ็นต์โดยไม่ต้องได้รับการร้องขอจากไคลเอ็นต์ก่อน และอนุญาตให้มีการแลกเปลี่ยนข้อความในขณะที่รักษาการเชื่อมต่อให้เปิดอยู่ ด้วยวิธีนี้ การสนทนาแบบสองทางอย่างต่อเนื่องสามารถเกิดขึ้นได้ระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ การสื่อสารมักจะทำผ่านพอร์ต TCP หมายเลข 443 (หรือ 80 ในกรณีของการเชื่อมต่อที่ไม่ปลอดภัย) ซึ่งเป็นประโยชน์สำหรับสภาพแวดล้อมที่บล็อกการเชื่อมต่ออินเทอร์เน็ตที่ไม่ใช่เว็บโดยใช้ไฟร์วอลล์นอกจากนี้ WebSocket ยังช่วยให้สามารถสตรีมข้อความบน TCP ได้ TCP เพียงอย่างเดียวจัดการกับสตรีมของไบต์โดยไม่มีแนวคิดเรื่องข้อความโดยธรรมชาติ การสื่อสารแบบสองทางระหว่างเบราว์เซอร์และเซิร์ฟเวอร์ที่คล้ายกันนี้เกิดขึ้นได้ในวิธีที่ไม่เป็นมาตรฐานโดยใช้เทคโนโลยีชั่วคราว เช่นCometหรือAdobe Flash Player [ 4 ]
เบราว์เซอร์ส่วนใหญ่รองรับโปรโตคอลนี้ รวมถึงGoogle Chrome , Firefox , Microsoft Edge , Internet Explorer , SafariและOpera [ 5 ]
ข้อกำหนดโปรโตคอล WebSocket กำหนดให้ws(WebSocket) และwss(WebSocket Secure) เป็น รูปแบบ ตัวระบุทรัพยากรแบบเดียวกัน (URI) ใหม่สองรูปแบบ[ 6 ]ซึ่งใช้สำหรับการเชื่อมต่อแบบไม่เข้ารหัสและแบบเข้ารหัสตามลำดับ นอกเหนือจากชื่อรูปแบบและส่วนย่อย (เช่น#ไม่ได้รับการสนับสนุน) ส่วนประกอบ URI ที่เหลือจะถูกกำหนดให้ใช้ไวยากรณ์ทั่วไปของ URI [ 7 ]
ประวัติศาสตร์
WebSocket ถูกอ้างอิงครั้งแรกในชื่อ TCPConnection ใน ข้อกำหนด HTML5โดยใช้เป็นตัวแทนสำหรับ API ซ็อกเก็ตแบบ TCP [ 8 ] ในเดือนมิถุนายน พ.ศ. 2551 ไมเคิล คาร์เตอร์ได้นำการอภิปรายหลายครั้งจนเกิดเป็นโปรโตคอลเวอร์ชันแรกที่รู้จักกันในชื่อ WebSocket [ 9 ] ก่อน WebSocket การสื่อสารแบบฟูลดูเพล็กซ์ผ่านพอร์ต 80 สามารถทำได้โดยใช้ ช่อง Cometอย่างไรก็ตาม การใช้งาน Comet นั้นไม่ง่าย และเนื่องจากการจับมือของ TCP และส่วนหัวของ HTTP ทำให้ไม่มีประสิทธิภาพสำหรับข้อความขนาดเล็ก โปรโตคอล WebSocket มีเป้าหมายเพื่อแก้ปัญหาเหล่านี้โดยไม่กระทบต่อข้อสมมติเรื่องความปลอดภัยของเว็บ ชื่อ "WebSocket" ถูกตั้งขึ้นโดยเอียน ฮิกสันและไมเคิล คาร์เตอร์ ในเวลาต่อมาไม่นานผ่านการทำงานร่วมกันในห้องแชท IRC #whatwg [ 10 ]และต่อมาเอียน ฮิกสัน ได้เขียนขึ้นเพื่อรวมไว้ในข้อกำหนด HTML5 ในเดือนธันวาคม พ.ศ. 2552 Google Chrome 4 เป็นเบราว์เซอร์แรกที่ให้การสนับสนุนมาตรฐานอย่างเต็มรูปแบบ โดยเปิดใช้งาน WebSocket เป็นค่าเริ่มต้น[ 11 ]การพัฒนาโปรโตคอล WebSocket ได้ถูกย้ายจากกลุ่ม W3C และWHATWGไปยัง IETF ในเดือนกุมภาพันธ์ พ.ศ. 2553 และมีการร่างฉบับแก้ไขสองครั้งภายใต้การดูแลของ Ian Hickson [ 12 ]
หลังจากที่โปรโตคอลดังกล่าวได้รับการเผยแพร่และเปิดใช้งานเป็นค่าเริ่มต้นในเบราว์เซอร์หลายตัวแล้วRFC 6455ก็ได้รับการสรุปขั้นสุดท้ายภายใต้การดูแลของ Ian Fette ในเดือนธันวาคม 2011
RFC 7692ได้นำเสนอส่วนขยายการบีบอัดข้อมูลสำหรับ WebSocket โดยใช้ อัลกอริธึม DEFLATEในแต่ละข้อความ
เว็บ API
แอปพลิเคชันเว็บ (เช่น เว็บเบราว์เซอร์) อาจใช้WebSocketอินเทอร์เฟซเพื่อรักษาการสื่อสารแบบสองทิศทางกับเซิร์ฟเวอร์ WebSocket [ 13 ]
ตัวอย่างลูกค้า
ในTypeScript
// เชื่อมต่อกับเซิร์ฟเวอร์const ws = new WebSocket ( "wss://game.example.com/scoreboard" );// รับ ArrayBuffer แทน Blob ws.binaryType = " arraybuffer " ;// ตั้งค่าตัวรับฟังเหตุการณ์ws.onopen = () => { console.log ( " Connection opened " ); ws.send ( " Hi server, please send me the score of yesterday's game" ) ; };ws.onmessage = ( event : MessageEvent ) = > { console.log ( " Data received" , event.data ) ; ws.close ( ); // เราได้รับคะแนน แล้วจึงไม่จำเป็นต้องเชื่อมต่ออีกต่อไป} ;ws.onclose = ( event : CloseEvent ) = > { console.log ( " Connection closed " , event.code , event.reason , event.wasClean ) ; } ;ws.onerror = () = > { console.log ( " Connection closed due to error" ) ; } ;อินเทอร์เฟซ WebSocket
| พิมพ์ | ชื่อ[ 14 ] | คำอธิบาย |
|---|---|---|
| ผู้สร้าง | ws = new WebSocket(url [, protocols ]) | เริ่มเปิดการจับมือ[ 15 ]
ข้อยกเว้น:
|
| วิธี | ws.send(data) | ส่ง ข้อความข้อมูล[ 16 ]
กลับ: ข้อยกเว้น:
หมายเหตุ: หากไม่สามารถส่งข้อมูลได้ (เช่น เนื่องจากต้องจัดเก็บไว้ในบัฟเฟอร์ แต่บัฟเฟอร์เต็ม) การเชื่อมต่อจะถูกปิดและ |
ws.close([ code ] [, reason ]) | เริ่มปิดการจับมือ[ 17 ]
กลับ: ข้อยกเว้น:
บันทึก:
| |
| เหตุการณ์ | ws.onopen = (event) => {}
| การเริ่มต้นการเชื่อมต่อสำเร็จแล้วประเภทeventคือEvent. |
ws.onmessage = (event) => {}
| ได้รับข้อความข้อมูลeventประเภทคือMessageEvent. เหตุการณ์นี้จะเกิดขึ้นก็ต่อเมื่อws.readyStateเป็นOPEN. [ 18 ]
| |
ws.onclose = (event) => {}
| การเชื่อมต่อ TCPพื้นฐานถูก ปิด ประเภทeventคือ[ 19 ] [ 20 ] [ 21 ] [ 22 ]CloseEvent
บันทึก:
| |
ws.onerror = (event) => {}
| การ เชื่อมต่อถูกปิดเนื่องจากข้อผิดพลาดeventประเภทคือ.Event | |
| คุณลักษณะ | ws.binaryType(สตริง) | ประเภทของevent.dataข้อมูลws.onmessageเมื่อได้รับข้อความข้อมูลไบนารี ตั้งค่าเริ่มต้นเป็น"blob"( Blobวัตถุ) อาจเปลี่ยนเป็น"arraybuffer"( ArrayBufferวัตถุ) [ 23 ] |
| คุณลักษณะแบบอ่านอย่างเดียว | ws.url(สตริง) | URL ที่ส่งให้กับWebSocketตัวสร้างพร้อมกับการแปลงดังต่อไปนี้:
|
ws.bufferedAmount(ตัวเลข) | จำนวนไบต์ของข้อมูลแอปพลิเคชัน (ข้อความ UTF-8 และข้อมูลไบนารี) ที่ถูกจัดคิวไว้ws.send()แต่ยังไม่ได้ส่งไปยังเครือข่าย ค่านี้จะรีเซ็ตเป็นศูนย์เมื่อส่งข้อมูลที่จัดคิวไว้ทั้งหมดแล้ว หากการเชื่อมต่อปิดลง ค่านี้จะเพิ่มขึ้นเรื่อยๆ ทุกครั้งที่มีการเรียกใช้ws.send()และจะไม่รีเซ็ตเป็นศูนย์[ 24 ] | |
ws.protocol(สตริง) | โปรโตคอลที่เซิร์ฟเวอร์ยอมรับหรือสตริงว่างหากprotocolsไม่ได้ระบุไว้ในWebSocketคอนสตรัคเตอร์ | |
ws.extensions(สตริง) | ส่วนขยาย ที่ เซิร์ฟเวอร์ยอมรับ | |
ws.readyState(ตัวเลข) | สถานะการเชื่อมต่อเป็นหนึ่งในค่าคงที่ด้านล่าง ตั้งค่าเริ่มต้นCONNECTINGเป็น[ 25 ] | |
| คงที่ | WebSocket.CONNECTING = 0 | ขณะนี้กำลังดำเนินการจับมือเปิดการเชื่อมต่อสถานะเริ่มต้นของการเชื่อมต่อ[ 26 ] [ 27 ] |
WebSocket.OPEN = 1 | การจับมือเริ่มต้นสำเร็จแล้วไคลเอนต์และเซิร์ฟเวอร์สามารถส่งข้อความถึงกันได้[ 28 ] [ 29 ] | |
WebSocket.CLOSING = 2 | ขณะนี้กำลังดำเนินการจับมือปิดอยู่ws.close()มีการเรียกใช้หรือได้รับข้อความปิด[ 30 ] [ 31 ] | |
WebSocket.CLOSED = 3 | การเชื่อมต่อ TCP พื้นฐานถูกปิด[ 32 ] [ 19 ] [ 20 ] |
โปรโตคอล

ขั้นตอน:
- การเริ่มต้นการเชื่อมต่อ :คำขอ HTTPและการตอบสนอง HTTP
- การแลกเปลี่ยน ข้อความแบบเฟรม : ข้อมูล, ข้อความปิง และข้อความปอง
- การปิดการเชื่อมต่อ : ข้อความปิด (คำขอจะถูกส่งกลับไปในข้อความตอบกลับ)
การจับมือเปิดงาน
ไคลเอนต์ส่งคำขอ HTTP ( เมธอด GET เวอร์ชัน ≥ 1.1 ) และเซิร์ฟเวอร์ส่งการตอบกลับ HTTPพร้อมรหัสสถานะ 101 ( การสลับโปรโตคอล ) เมื่อสำเร็จ ไคลเอนต์ HTTP และ WebSocket สามารถเชื่อมต่อกับเซิร์ฟเวอร์โดยใช้พอร์ตเดียวกันได้ เนื่องจากแฮนด์เชคเริ่มต้นใช้ HTTP การส่งส่วนหัว HTTP เพิ่มเติม (ที่ไม่ได้อยู่ในตารางด้านล่าง) สามารถทำได้ ส่วนหัว HTTP สามารถส่งได้ในลำดับใดก็ได้ หลังจาก ตอบกลับ HTTP การสลับโปรโตคอลแล้ว แฮนด์เชคเริ่มต้นจะเสร็จสมบูรณ์ โปรโตคอล HTTP จะหยุดใช้งาน และการสื่อสารจะเปลี่ยนไปใช้โปรโตคอลแบบเฟรมไบนารี[ 33 ] [ 34 ]
ด้านข้าง | ส่วนหัว | ค่า | บังคับ |
|---|---|---|---|
ขอ | ต้นกำเนิด[ 35 ] | แตกต่างกันไป | ใช่ (สำหรับไคลเอ็นต์บนเว็บเบราว์เซอร์) |
| โฮสต์[ 36 ] | แตกต่างกันไป | ใช่ | |
| Sec-WebSocket-Version [ 37 ] | 13 | ||
| Sec-WebSocket-Key [ 38 ] | base64 -encode(16 random bytes) | ||
การตอบสนอง | Sec-WebSocket-Accept [ 39 ] | base64-encode( SHA1 (Sec-WebSocket-Key + " 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 " )) [ b ] | |
ทั้งคู่ | การเชื่อมต่อ[ 40 ] [ 41 ] | อัปเกรด | |
| อัปเกรด[ 42 ] [ 43 ] | เว็บซ็อกเก็ต | ||
| Sec-WebSocket-Protocol [ 44 ] | คำขออาจมีรายการสตริงที่คั่นด้วยเครื่องหมายจุลภาค (เรียงลำดับตามความชอบ) ซึ่งระบุโปรโตคอลระดับแอปพลิ เคชัน (ที่สร้างขึ้นบนข้อความข้อมูล WebSocket) ที่ไคลเอ็นต์ต้องการใช้ หากไคลเอ็นต์ส่งส่วนหัวนี้ การตอบสนองของเซิร์ฟเวอร์จะต้องเป็นหนึ่งในค่าจากรายการดังกล่าว | เลขที่ | |
| ส่วนขยาย Sec-WebSocket [ 45 ] [ 46 ] [ 47 ] [ 48 ] | ใช้สำหรับเจรจาต่อรองส่วนขยายระดับโปรโตคอล ไคลเอนต์อาจร้องขอส่วนขยายของโปรโตคอล WebSocket โดยการระบุรายการส่วนขยายที่คั่นด้วยเครื่องหมายจุลภาค (เรียงลำดับตามความชอบ) แต่ละส่วนขยายอาจมีพารามิเตอร์ (เช่น foo=4) เซิร์ฟเวอร์อาจยอมรับส่วนขยายบางส่วนหรือทั้งหมดที่ไคลเอนต์ร้องขอ ฟิลด์นี้อาจปรากฏหลายครั้งในคำขอ (ในเชิงตรรกะเทียบเท่ากับการปรากฏเพียงครั้งเดียวที่มีค่าทั้งหมด) และต้องไม่ปรากฏมากกว่าหนึ่งครั้งในคำตอบ |
ตัวอย่างคำขอ: [ 34 ]
GET /chat HTTP / 1.1 Host : server.example.com Upgrade : websocket Connection : Upgrade Sec-WebSocket-Key : dGhlIHNhbXBsZSBub25jZQ== Origin : http://example.com Sec-WebSocket-Protocol : chat, superchat Sec-WebSocket-Version : 13ตัวอย่างการตอบกลับ: [ 34 ]
HTTP / 1.1 101 การสลับโปรโตคอล อัปเกรด : websocket การเชื่อมต่อ: อัปเกรดSec-WebSocket-Accept : s3pPLMBiTxaQ9kYGzzhZRbK+xOo= Sec-WebSocket-Protocol : chatโค้ด Pythonต่อไปนี้สร้างค่าSec-WebSocket-Keyสุ่ม
import base64 import osพิมพ์( base64.b64encode ( os.urandom ( 16 ) ) )โค้ด Python ต่อไปนี้คำนวณSec-WebSocket-Acceptโดยใช้ข้อมูลSec-WebSocket-Keyจากคำขอตัวอย่างข้างต้น
import base64 import hashlibKEY : bytes = b "dGhlIHNhbXBsZSBub25jZQ==" MAGIC : bytes = b "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" print ( base64 . b64encode ( hashlib . sha1 ( KEY + MAGIC ) . digest ()))Sec-WebSocket-KeyและSec-WebSocket-Acceptมีจุดประสงค์เพื่อป้องกันไม่ให้พร็อกซีแคช ส่งการสนทนา WebSocket ก่อนหน้าซ้ำ[ 49 ]และไม่ได้ให้การตรวจสอบสิทธิ์ ความเป็นส่วนตัว หรือความสมบูรณ์ใดๆ
แม้ว่าเซิร์ฟเวอร์บางแห่งจะยอมรับส่วนหัว Sec-WebSocket-Key ที่สั้นSec-WebSocket-Keyแต่เซิร์ฟเวอร์สมัยใหม่หลายแห่งจะปฏิเสธคำขอพร้อมแสดงข้อผิดพลาด "ส่วนหัว Sec-WebSocket-Key ไม่ถูกต้อง"
ข้อความแบบเฟรม
หลังจากขั้นตอนการเชื่อมต่อเริ่มต้นเสร็จสิ้นแล้ว ไคลเอนต์และเซิร์ฟเวอร์สามารถส่ง ข้อความข้อมูล (ข้อความธรรมดาหรือไบนารี) และข้อความควบคุม ( Close , Ping , Pong ) ถึงกัน ได้ตลอดเวลาข้อความหนึ่งข้อความประกอบด้วยหนึ่งเฟรมหากไม่มีการแบ่งส่วนหรืออย่างน้อยสองเฟรมหากมีการแบ่งส่วน
การแบ่งส่วนจะแบ่งข้อความออกเป็นสองเฟรมขึ้นไปช่วยให้สามารถส่งข้อความที่มีข้อมูลเริ่มต้นพร้อมใช้งาน แต่ไม่ทราบความยาวทั้งหมด หากไม่มีการแบ่งส่วน ข้อความทั้งหมดจะต้องส่งในเฟรมเดียว ดังนั้นจึงจำเป็นต้องมีความยาวทั้งหมดก่อนที่จะส่งไบต์แรก ซึ่งต้องใช้บัฟเฟอร์[ 50 ] มีการเสนอให้ขยายคุณสมบัตินี้เพื่อให้สามารถมัลติเพล็กซ์สตรีมหลายสตรีมพร้อมกันได้ (เช่น เพื่อหลีกเลี่ยงการผูกขาดซ็อกเก็ตสำหรับ เพย์โหลดขนาดใหญ่เพียงรายการเดียว) แต่การขยายโปรโตคอลนี้ไม่ได้รับการยอมรับ[ 51 ]
- ข้อความที่ไม่แตกแยกประกอบด้วยเฟรมหนึ่งเฟรมที่มี
FIN = 1และopcode ≠ 0. - ข้อความที่ถูกแบ่งส่วนประกอบด้วยเฟรมหนึ่งที่มี
FIN = 0และopcode ≠ 0ตามด้วยเฟรมที่มีFIN = 0และ ตั้งแต่ศูนย์เฟรมขึ้นไปopcode = 0และปิดท้ายด้วยเฟรมหนึ่งที่มีFIN = 1และopcode = 0
โครงสร้างเฟรม
| ค่าออฟเซ็ต (บิต) | ฟิลด์[ 52 ] | ขนาด(บิต) | คำอธิบาย | |
|---|---|---|---|---|
| 0 | FIN [ 53 ] | 1 |
| |
| 1 | อาร์เอสวี1 | 1 | สงวนไว้ ต้องเป็น 0เว้นแต่จะกำหนดโดยส่วนขยาย หากได้รับค่าที่ไม่ใช่ศูนย์และไม่มีส่วนขยายที่เจรจาไว้กำหนดความหมายของค่าที่ไม่ใช่ศูนย์ดังกล่าว การเชื่อมต่อจะต้องถูกปิด[ 54 ] | |
| 2 | อาร์เอสวี2 | 1 | ||
| 3 | อาร์เอสวี3 | 1 | ||
| 4 | รหัสปฏิบัติการ | 4 | ดูรหัสคำสั่งด้านล่าง | |
| 8 | หน้ากาก[ 55 ] | 1 |
| |
| 9 | ความยาวของเพย์โหลด[ 56 ] | 7, 7+16 หรือ 7+64 | ความยาวของข้อมูล (ข้อมูลเพิ่มเติม + ข้อมูลแอปพลิเคชัน) ในหน่วยไบต์
| |
| แตกต่างกันไป | คีย์การมาสก์[ 57 ] | 0 หรือ 32 | ค่า nonce แบบสุ่มจะมีอยู่หากฟิลด์ที่ถูกปิดบังมีค่าเป็น 1 ไคลเอนต์จะสร้างคีย์การปิดบังสำหรับทุกเฟรมที่ถูกปิดบัง | |
| เพย์โหลด | ข้อมูลส่วนขยาย | ความยาวของข้อมูล (ไบต์) | ต้องว่างเปล่าเว้นแต่จะถูกกำหนดโดยส่วนขยาย | |
| ข้อมูลแอปพลิเคชัน | ขึ้นอยู่กับโอเปอเรชันโค้ด | |||
รหัสปฏิบัติการ
| ประเภทเฟรม[ 58 ] | รหัสปฏิบัติการ[ 59 ] | ที่เกี่ยวข้อง | คำอธิบาย | วัตถุประสงค์ | แตกเป็นชิ้นเล็กชิ้นน้อยได้ | ความยาวสูงสุดของข้อมูล (ไบต์) | |
|---|---|---|---|---|---|---|---|
| เฟรมต่อเนื่อง | 0 | เฟรมที่ไม่ใช่เฟรมแรกของข้อความที่ถูกตัดแบ่ง | การแบ่งส่วนข้อความ | 2 63 − 1 [ c ] | |||
| เฟรมที่ไม่ใช่เฟรมควบคุม | ข้อความ | 1 | send(),onmessage | ข้อความที่เข้ารหัสแบบ UTF-8 | ข้อความข้อมูล | ใช่ | |
| ไบนารี | 2 | ข้อมูลไบนารี | |||||
| 3–7 | สงวนไว้สำหรับเฟรมที่ไม่ใช่การควบคุมเพิ่มเติม อาจกำหนดโดยส่วนขยาย[ 60 ] | ||||||
| เฟรมควบคุม[ 61 ] | ปิด | 8 | close(),onclose | การจับมือปิด ของ WebSocket เริ่มต้นเมื่อมีการส่งหรือรับเฟรมClose [ 62 ] อาจช่วยป้องกันการสูญเสียข้อมูลโดยการเสริมการจับมือปิดของ TCP [ 63 ] ไม่สามารถส่งเฟรมใด ๆ ได้หลังจากส่ง เฟรม Close แล้วหากได้รับเฟรมClose และไม่มี การส่งเฟรมClose ก่อนหน้านี้ จะต้องส่งเฟรม Close ตอบกลับ (โดยทั่วไปคือการสะท้อนรหัสสถานะที่ได้รับ) เพย์โหลดเป็นตัวเลือก แต่ถ้ามีอยู่ จะต้องเริ่มต้นด้วย รหัสสถานะจำนวนเต็มที่ไม่ระบุเครื่องหมายแบบ big-endian สองไบต์ตามด้วยข้อความเหตุผลที่เข้ารหัส UTF-8 ซึ่งมีความยาวไม่เกิน 123 ไบต์[ 64 ] | สถานะโปรโตคอล | เลขที่ | 125 |
| ปิง | 9 | อาจใช้สำหรับการวัดความหน่วงการรักษาการเชื่อมต่อและการเต้นของหัวใจทั้งสองฝ่ายสามารถส่ง ping (ด้วยเพย์โหลดใดก็ได้) ฝ่ายที่ได้รับ ping จะต้องส่ง pong กลับมาโดยเร็วที่สุดเท่าที่จะทำได้ด้วยเพย์โหลดเดียวกันควรละเว้น pong หากไม่มีการส่ง ping มาก่อน[ 65 ] [ 66 ] [ 67 ] | |||||
| ปอง | 10 | ||||||
| 11–15 | สงวนไว้สำหรับเฟรมควบคุมเพิ่มเติม อาจกำหนดโดยส่วนขยาย[ 60 ] | ||||||
การซ่อนข้อมูลจากไคลเอ็นต์ไปยังเซิร์ฟเวอร์
ไคลเอนต์ต้องมาสก์เฟรมทั้งหมดที่ส่งไปยังเซิร์ฟเวอร์ เซิร์ฟเวอร์ต้องไม่มาสก์เฟรมใดๆ ที่ส่งไปยังไคลเอนต์[ 68 ]การมาสก์เฟรมใช้การดำเนินการXOR ระหว่างเพย์โหลดและคีย์การมาสก์รหัสเทียมต่อไปนี้อธิบายอัลกอริทึมที่ใช้ในการมาสก์และยกเลิกการมาสก์เฟรม[ 57 ]
สำหรับ i ตั้งแต่ 0 ถึง payload_length − 1 payload[i] := payload[i] xor masking_key[i mod 4]
รหัสสถานะ
| ช่วง[ 69 ] | อนุญาตให้อยู่ในกรอบ ปิด | รหัส | คำอธิบาย |
|---|---|---|---|
| 0–999 | เลขที่ | ยังไม่ได้ใช้งาน | |
| 1000–2999 (พิธีสาร) | ใช่ | 1000 | การปิดตามปกติ |
| 1001 | กำลังออกจากระบบ (เช่น ปิดแท็บเบราว์เซอร์; เซิร์ฟเวอร์ล่ม) | ||
| 1002 | เกิดข้อผิดพลาดของโปรโตคอล | ||
| 1003 | ข้อมูลไม่รองรับ (เช่น ปลายทางเข้าใจเฉพาะข้อความ แต่ได้รับข้อมูลไบนารี) | ||
| เลขที่ | 1004 | สงวนไว้สำหรับการใช้งานในอนาคต | |
| 1005 | ไม่ได้รับรหัสใดๆ | ||
| 1006 | การเชื่อมต่อถูกปิดอย่างผิดปกติ (เช่น การจับมือเพื่อปิดการเชื่อมต่อไม่เกิดขึ้น) | ||
| ใช่ | 1007 | ข้อมูลเพย์โหลดไม่ถูกต้อง (เช่น ข้อมูลที่ไม่ใช่ UTF-8 ในข้อความ) | |
| 1008 | มีการละเมิดนโยบาย | ||
| 1009 | ข้อความมีขนาดใหญ่เกินไป | ||
| 1010 | ส่วนขยายไม่รองรับ ลูกค้าควรระบุส่วนขยายที่คาดว่าเซิร์ฟเวอร์จะรองรับไว้ในข้อมูลที่ส่งไป | ||
| 1011 | เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์ | ||
| เลขที่ | 1015 | การเชื่อมต่อ TLS ล้มเหลว | |
| 3000–3999 | ใช่ | สงวนไว้สำหรับไลบรารี เฟรมเวิร์ก และแอปพลิเคชัน ลงทะเบียนโดยตรงกับ IANA | |
| 4000–4999 | สำหรับใช้ส่วนตัว |
การบีบอัดและการขยาย
ส่วนขยาย นี้permessage-deflateอนุญาตให้บีบอัดข้อความข้อมูลโดยใช้ อัลกอริธึม DEFLATEตัวอย่างเช่น ในระหว่างการจับมือเริ่มต้น ไคลเอนต์และเซิร์ฟเวอร์อาจใช้ส่วนหัวต่อไปนี้เพื่อเปิดใช้งานส่วนขยายRSV1ฟิลด์ของเฟรมแรกของข้อความข้อมูลจะต้องถูกตั้งค่าเพื่อระบุว่าข้อมูลเพย์โหลดถูกบีบอัด[ 71 ]
Sec-WebSocket-Extensions: permessage-deflateตัวอย่างการใช้งานเซิร์ฟเวอร์
ในภาษา Python
หมายเหตุ: ฟังก์ชันนี้recv()จะส่งคืนข้อมูลได้สูงสุดตามจำนวนไบต์ที่ร้องขอ เพื่อความอ่านง่าย โค้ดจึงละเว้นส่วนนี้ ดังนั้นอาจเกิดข้อผิดพลาดได้ในสภาวะเครือข่ายที่ไม่เหมาะสม
import base64 import hashlib import struct from typing import Optional from socket import socket as Socketdef handle_websocket_connection ( ws : Socket ) -> None : # ยอมรับการเชื่อมต่อconn , addr = ws . accept ()# รับและแยกวิเคราะห์ คีย์คำขอ HTTP : ตัวเลือก[ ไบต์] = ไม่มีสำหรับบรรทัดในconn.recv ( 4096 ) .split ( b " \ r\n " ) : ถ้าบรรทัดเริ่มต้นด้วย( b "Sec-WebSocket-Key" ): คีย์= บรรทัด. split ()[ - 1 ]หากคีย์เป็นNone ให้แสดงข้อผิดพลาดValueError ( "ไม่พบคีย์ Sec-WebSocket" )# ส่งการตอบสนอง HTTP sec_accept = base64 . b64encode ( hashlib . sha1 ( key + b "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ) . digest ()) conn . sendall ( b " \r\n " . join ([ b "HTTP/1.1 101 Switching Protocols" , b "Connection: Upgrade" , b "Upgrade: websocket" , b "Sec-WebSocket-Accept: " + sec_accept , b "" , b "" , ]) )# ถอดรหัสและพิมพ์เฟรมในขณะที่True เป็นจริง: byte0, byte1 = conn.recv ( 2 ) fin : int = byte0 >> 7 opcode : int = byte0 & 0b1111 masked : int = byte1 >> 7 assert masked , " ไคลเอนต์ต้องมาสก์เฟรมทั้งหมด" ถ้าopcode >= 8 : assert fin , "เฟรมควบคุมไม่สามารถแบ่งย่อยได้"# ขนาดเพย์โหลดpayload_size : int = byte1 & 0b111_1111 ถ้าpayload_size == 126 : payload_size , = struct . unpack ( ">H" , conn . recv ( 2 )) assert payload_size > 125 , "ต้องใช้จำนวนบิตขั้นต่ำ" elif payload_size == 127 : payload_size , = struct . unpack ( ">Q" , conn . recv ( 8 )) assert payload_size > 2 ** 16 - 1 , "ต้องใช้จำนวนบิตขั้นต่ำ" assert payload_size <= 2 ** 63 - 1 , "บิตที่มีนัยสำคัญที่สุดต้องเป็นศูนย์" ถ้าopcode >= 8 : assert payload_size <= 125 , "เฟรมควบคุมต้องมีขนาดไม่เกิน 125 ไบต์"# เปิดเผยmasking_key : bytes = conn . recv ( 4 ) payload : bytearray = bytearray ( conn . recv ( payload_size )) for i in range ( payload_size ): payload [ i ] = payload [ i ] ^ masking_key [ i % 4 ]พิมพ์( "เฟรมที่ได้รับ" , FIN , opcode , payload )ถ้า__name__ == "__main__" : # ยอมรับการเชื่อมต่อ TCP บนอินเทอร์เฟซใดก็ได้ที่พอร์ต 80 ws : Socket = Socket () ws . bind (( "" , 80 )) ws . listen ()จัดการการเชื่อมต่อเว็บซ็อกเก็ต( ws )การรองรับเบราว์เซอร์
โปรโตคอล WebSocket เวอร์ชันที่ปลอดภัยถูกนำไปใช้ใน Firefox 6 [ 72 ] Safari 6, Google Chrome 14 [ 73 ] Opera 12.10 และInternet Explorer 10 [ 74 ] รายงานชุดทดสอบโปรโตคอลโดยละเอียด[ 75 ]แสดงรายการการปฏิบัติตามโปรโตคอลเฉพาะของเบราว์เซอร์เหล่านั้น
โปรโตคอลเวอร์ชันเก่าที่มีความปลอดภัยน้อยกว่าถูกนำมาใช้ใน Opera 11 และSafari 5 รวมถึง Safari เวอร์ชันมือถือในiOS 4.2 [ 76 ] BlackBerry Browser ใน OS7 ใช้ WebSockets [ 77 ]เนื่องจากมีช่องโหว่ จึงถูกปิดใช้งานใน Firefox 4 และ 5 [ 78 ]และ Opera 11 [ 79 ] นักพัฒนาสามารถตรวจสอบการจับมือของ WebSocket รวมถึงเฟรม WebSocket ได้โดยใช้เครื่องมือสำหรับนักพัฒนาเบราว์เซอร์[ 80 ]
| เวอร์ชันโปรโตคอล | วันที่ร่าง | อินเทอร์เน็ตเอ็กซ์พลอเรอร์ | Firefox [ 81 ] (พีซี) | Firefox (แอนดรอยด์) | โครม(พีซี, มือถือ) | Safari (Mac, iOS) | โอเปรา(พีซี, มือถือ) | เบราว์เซอร์ Android |
|---|---|---|---|---|---|---|---|---|
| ฮิกซี่-75 | 4 กุมภาพันธ์ 2553 | 4 | 5.0.0 | |||||
| ฮิกซี่-76 ไฮบิ-00 | 6 พฤษภาคม 2553 23 พฤษภาคม 2553 | 4.0 (ปิดใช้งาน) | 6 | 5.0.1 | 11.00 น. (ผู้พิการ) | |||
| hybi-07 , v7 | 22 เมษายน 2554 | 6 [ 82 ] [ d ] | ||||||
| ไฮบิ-10 , v8 | วันที่ 11 กรกฎาคม 2554 | 7 [ 84 ] [ d ] | 7 | 14 [ 85 ] | ||||
| RFC 6455เวอร์ชัน 13 | ธันวาคม พ.ศ. 2554 | 10 [ 86 ] | 11 | 11 | 16 [ 87 ] | 6 | 12.10 [ 88 ] | 4.4 |
การใช้งานเซิร์ฟเวอร์
- Nginxรองรับ WebSockets มาตั้งแต่ปี 2013 โดยใช้งานในเวอร์ชัน 1.3.13 [ 89 ]รวมถึงการทำหน้าที่เป็นreverse proxyและload balancerของแอปพลิเคชัน WebSocket [ 90 ]
- Apache HTTP Serverรองรับ WebSockets ตั้งแต่เดือนกรกฎาคม พ.ศ. 2556 โดยเริ่มใช้งานในเวอร์ชัน 2.4.5 [ 91 ] [ 92 ]
- Internet Information Servicesได้เพิ่มการสนับสนุน WebSockets ในเวอร์ชัน 8 ซึ่งเปิดตัวพร้อมกับWindows Server 2012 [ 93 ]
- lighttpdรองรับ WebSockets มาตั้งแต่ปี 2017 โดยนำมาใช้ใน lighttpd เวอร์ชัน 1.4.46 [ 94 ] lighttpd mod_proxy สามารถทำหน้าที่เป็น reverse proxy และ load balancer สำหรับแอปพลิเคชัน WebSocket ได้ lighttpd mod_wstunnel สามารถทำหน้าที่เป็น WebSocket endpoint เพื่อส่งข้อมูลใดๆ ก็ได้ รวมถึงข้อมูลใน รูปแบบ JSONไปยังแอปพลิเคชันแบ็กเอนด์ lighttpd รองรับ WebSockets ผ่าน HTTP/2 มาตั้งแต่ปี 2022 โดยนำมาใช้ใน lighttpd เวอร์ชัน 1.4.65 [ 95 ]
- Eclipse Mosquittoเป็นโบรกเกอร์ MQTTแต่รองรับ MQTT ผ่าน WebSocket ดังนั้นจึงอาจถือได้ว่าเป็นรูปแบบหนึ่งของการใช้งาน WebSocket
ASP.NET Core รองรับ WebSockets โดยใช้app.UseWebSockets();middleware [ 96 ]
ข้อควรพิจารณาด้านความปลอดภัย
ต่างจากคำขอ HTTP ข้ามโดเมนทั่วไป คำขอ WebSocket ไม่ได้ถูกจำกัดโดยนโยบายต้นทางเดียวกันดังนั้น เซิร์ฟเวอร์ WebSocket ต้องตรวจสอบความถูกต้องของส่วนหัว "Origin" กับต้นทางที่คาดหวังในระหว่างการสร้างการเชื่อมต่อ เพื่อหลีกเลี่ยงการโจมตีการโจรกรรม WebSocket ข้ามไซต์ (คล้ายกับการปลอมแปลงคำขอข้ามไซต์ ) ซึ่งอาจเกิดขึ้นได้เมื่อการเชื่อมต่อได้รับการตรวจสอบสิทธิ์ด้วยคุกกี้หรือการตรวจสอบสิทธิ์ HTTP ควรใช้โทเค็นหรือกลไกการป้องกันที่คล้ายกันเพื่อตรวจสอบสิทธิ์การเชื่อมต่อ WebSocket เมื่อมีการถ่ายโอนข้อมูลที่ละเอียดอ่อน (ส่วนตัว) ผ่าน WebSocket [ 97 ]ตัวอย่างจริงของช่องโหว่พบเห็นได้ในปี 2020 ในรูปแบบของCable Haunt
การสำรวจพร็อกซี
การใช้งานไคลเอ็นต์ของโปรโตคอล WebSocket จะพยายามตรวจจับว่าเอเจนต์ผู้ใช้ได้รับการกำหนดค่าให้ใช้พร็อกซีเมื่อเชื่อมต่อกับโฮสต์และพอร์ตปลายทางหรือไม่ และหากเป็นเช่นนั้น จะใช้ วิธี HTTP CONNECTเพื่อสร้างอุโมงค์แบบถาวร
โปรโตคอล WebSocket ไม่รับรู้ถึงพร็อกซีเซิร์ฟเวอร์และไฟร์วอลล์ พร็อกซีเซิร์ฟเวอร์บางตัวโปร่งใสและใช้งานได้ดีกับ WebSocket ในขณะที่บางตัวจะขัดขวางการทำงานของ WebSocket ทำให้การเชื่อมต่อล้มเหลว ในบางกรณี อาจต้องมีการกำหนดค่าพร็อกซีเซิร์ฟเวอร์เพิ่มเติม และพร็อกซีเซิร์ฟเวอร์บางตัวอาจต้องได้รับการอัปเกรดเพื่อรองรับ WebSocket
หากทราฟฟิก WebSocket ที่ไม่ได้เข้ารหัสไหลผ่านพร็อกซีเซิร์ฟเวอร์แบบชัดเจนหรือแบบโปร่งใสที่ไม่มีการสนับสนุน WebSockets การเชื่อมต่อก็มีแนวโน้มที่จะล้มเหลว[ 98 ]
หากใช้การเชื่อมต่อ WebSocket ที่เข้ารหัส การใช้Transport Layer Security (TLS) ในการเชื่อมต่อ WebSocket Secure จะช่วยให้มั่นใจได้ว่าHTTP CONNECTมีการส่งคำสั่งเมื่อเบราว์เซอร์ถูกกำหนดค่าให้ใช้พร็อกซีเซิร์ฟเวอร์แบบระบุชัดเจน ซึ่งจะสร้างอุโมงค์ที่ให้การสื่อสาร TCP ระดับต่ำแบบ end-to-end ผ่านพร็อกซี HTTP ระหว่างไคลเอ็นต์ WebSocket Secure และเซิร์ฟเวอร์ WebSocket ในกรณีของพร็อกซีเซิร์ฟเวอร์แบบโปร่งใส เบราว์เซอร์จะไม่ทราบถึงพร็อกซีเซิร์ฟเวอร์ ดังนั้นจึงไม่มีHTTP CONNECTการส่งคำสั่งใดๆ อย่างไรก็ตาม เนื่องจากข้อมูลที่ส่งผ่านเครือข่ายถูกเข้ารหัส พร็อกซีเซิร์ฟเวอร์แบบโปร่งใสระดับกลางอาจอนุญาตให้ข้อมูลที่เข้ารหัสผ่านไปได้ ดังนั้นจึงมีโอกาสมากขึ้นที่การเชื่อมต่อ WebSocket จะสำเร็จหากใช้ WebSocket Secure การใช้การเข้ารหัสไม่ได้ปราศจากต้นทุนด้านทรัพยากร แต่โดยทั่วไปแล้วจะให้ผลสำเร็จสูงสุด เนื่องจากข้อมูลจะเดินทางผ่านอุโมงค์ที่ปลอดภัย
ร่างกลางปี 2010 (เวอร์ชัน hixie-76) ทำลายความเข้ากันได้กับพร็อกซีแบบย้อนกลับและเกตเวย์โดยการรวมข้อมูลคีย์แปดไบต์ไว้หลังส่วนหัว แต่ไม่ได้โฆษณาข้อมูลนั้นในContent-Length: 8ส่วนหัว[ 99 ]ข้อมูลนี้ไม่ได้ถูกส่งต่อโดยตัวกลางทั้งหมด ซึ่งอาจนำไปสู่ความล้มเหลวของโปรโตคอล ร่างที่ใหม่กว่า (เช่น hybi-09 [ 100 ] ) ได้ใส่ข้อมูลคีย์ไว้ในSec-WebSocket-Keyส่วนหัว ซึ่งแก้ปัญหานี้ได้
ดูเพิ่มเติม
หมายเหตุ
- ^อัลกอริทึมการแยกวิเคราะห์ URLอธิบายไว้ที่ https://url.spec.whatwg.org/#concept-basic-url-parser
- ^เครื่องหมายบวกแสดงถึงเชื่อมต่อสตริง
- ^ข้อกำหนดระบุข้อจำกัดไว้อย่างชัดเจนเฉพาะเฟรมควบคุมเท่านั้น ดังนั้นเฟรมอื่นๆ ทั้งหมดจึงถูกจำกัดด้วยขีดจำกัดของโปรโตคอลที่ 63 บิตสำหรับความยาวของเพย์โหลด (เนื่องจากบิตที่มีนัยสำคัญที่สุดต้องเป็นศูนย์)
- ^ a bเบราว์เซอร์เวอร์ชัน 6–10 ที่ใช้ Gecko จะใช้ WebSocket object เป็น "MozWebSocket" [ 83 ]ซึ่งต้องใช้โค้ดเพิ่มเติมเพื่อผสานรวมกับโค้ดที่เปิดใช้งาน WebSocket ที่มีอยู่
ลิงก์ภายนอก
- กลุ่มงานไฮเปอร์เท็กซ์แบบสองทิศทาง (HyBi) ของ IETF
- RFC 6455โปรโตคอล WebSocket – มาตรฐานที่เสนอโดยกลุ่มทำงาน IETF HyBi
- โปรโตคอล WebSocket – ฉบับร่างทางอินเทอร์เน็ต เผยแพร่โดยกลุ่มทำงาน IETF HyBi
- โปรโตคอล WebSocket – ข้อเสนอโปรโตคอลดั้งเดิมโดย Ian Hickson
- เอกสาร WebSocket API ฉบับร่างที่จัดเก็บไว้เมื่อวันที่ 7 มิถุนายน 2015 บนWayback Machine – เอกสาร ร่างข้อกำหนด API ของW3C
- ข้อกำหนด API WebSocket – W3C Candidate Recommendationของ API
- WebSocket.org เก็บถาวรเมื่อ 2018-09-16 ที่Wayback Machineตัวอย่างการใช้งาน WebSocket, การทดสอบลูปแบ็ก, ข้อมูลทั่วไป และชุมชน
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ เว็บซ็อกเก็ต
WebSocket เป็น โปรโตคอลการสื่อสาร คอมพิวเตอร์ ที่ให้ ช่องทางการสื่อสาร แบบสองทิศทาง ผ่านการเชื่อมต่อ Transmission Control Protocol (TCP) เดียว โปรโตคอลนี้ได้รับการกำหนดมาตรฐานโดย...
ประวัติศาสตร์
WebSocket ถูกอ้างอิงครั้งแรกในชื่อ TCPConnection ใน ข้อกำหนด HTML5 โดยใช้เป็นตัวแทนสำหรับ API ซ็อกเก็ตแบบ TCP [ 8 ] ในเดือนมิถุนายน พ.ศ.
เว็บ API
แอปพลิเคชันเว็บ (เช่น เว็บเบราว์เซอร์) อาจใช้ WebSocket อินเทอร์เฟซเพื่อรักษาการสื่อสารแบบสองทิศทางกับเซิร์ฟเวอร์ WebSocket [ 13 ]
การจับมือเปิดงาน
ไคลเอนต์ส่ง คำขอ HTTP ( เมธอด GET เวอร์ชัน ≥ 1.1 ) และเซิร์ฟเวอร์ส่ง การตอบกลับ HTTP พร้อม รหัสสถานะ 101 ( การสลับโปรโตคอล ) เมื่อสำเร็จ ไคลเอนต์ HTTP และ WebSocket สามารถเชื่อมต่อกับเซิร์ฟเวอร์โดยใช้พอร์ตเดียวกันได้ เนื่องจากแฮนด์เชคเริ่มต้นใช้ HTTP...