ÐÑоÑокол WebSocket («веб-ÑокеÑ»), опиÑаннÑй в ÑпеÑиÑикаÑии RFC 6455, обеÑпеÑÐ¸Ð²Ð°ÐµÑ Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð¾ÑÑÑ Ð¾Ð±Ð¼ÐµÐ½Ð° даннÑми Ð¼ÐµÐ¶Ð´Ñ Ð±ÑаÑзеÑом и ÑеÑвеÑом ÑеÑез поÑÑоÑнное Ñоединение. ÐаннÑе пеÑедаÑÑÑÑ Ð¿Ð¾ Ð½ÐµÐ¼Ñ Ð² обоиÑ
напÑавлениÑÑ
в виде «пакеÑов», без ÑазÑÑва ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¸ дополниÑелÑнÑÑ
HTTP-запÑоÑов.
WebSocket оÑобенно Ñ Ð¾ÑÐ¾Ñ Ð´Ð»Ñ ÑеÑвиÑов, коÑоÑÑе нÑждаÑÑÑÑ Ð² поÑÑоÑнном обмене даннÑми, напÑÐ¸Ð¼ÐµÑ Ð¾Ð½Ð»Ð°Ð¹Ð½ игÑÑ, ÑоÑговÑе плоÑадки, ÑабоÑаÑÑие в ÑеалÑном вÑемени, и Ñ.д.
ÐÑоÑÑой пÑимеÑ
ЧÑÐ¾Ð±Ñ Ð¾ÑкÑÑÑÑ Ð²ÐµÐ±-ÑокеÑ-Ñоединение, нам нÑжно ÑоздаÑÑ Ð¾Ð±ÑÐµÐºÑ new WebSocket, Ñказав в url-адÑеÑе ÑпеÑиалÑнÑй пÑоÑокол ws:
let socket = new WebSocket("ws://javascript.info");
Также ÑÑÑеÑÑвÑÐµÑ Ð¿ÑоÑокол wss://, иÑполÑзÑÑÑий ÑиÑÑование. ÐÑо как HTTPS Ð´Ð»Ñ Ð²ÐµÐ±-ÑокеÑов.
wss://ÐÑоÑокол wss:// не ÑолÑко иÑполÑзÑÐµÑ ÑиÑÑование, но и Ð¾Ð±Ð»Ð°Ð´Ð°ÐµÑ Ð¿Ð¾Ð²ÑÑенной надÑжноÑÑÑÑ.
ÐÑо поÑомÑ, ÑÑо даннÑе ws:// не заÑиÑÑованÑ, Ð²Ð¸Ð´Ð½Ñ Ð´Ð»Ñ Ð»Ñбого поÑÑедника. СÑаÑÑе пÑокÑи-ÑеÑвеÑÑ Ð½Ðµ знаÑÑ Ð¾ WebSocket, они могÑÑ ÑвидеÑÑ Â«ÑÑÑаннÑе» заголовки и закÑÑÑÑ Ñоединение.
С дÑÑгой ÑÑоÑонÑ, wss:// â ÑÑо WebSocket повеÑÑ
TLS (Ñак же, как HTTPS â ÑÑо HTTP повеÑÑ
TLS), безопаÑнÑй ÑÑанÑпоÑÑнÑй ÑÑÐ¾Ð²ÐµÐ½Ñ ÑиÑÑÑÐµÑ Ð´Ð°Ð½Ð½Ñе Ð¾Ñ Ð¾ÑпÑавиÑÐµÐ»Ñ Ð¸ ÑаÑÑиÑÑовÑÐ²Ð°ÐµÑ Ð½Ð° ÑÑоÑоне полÑÑаÑелÑ. ÐакеÑÑ Ð´Ð°Ð½Ð½ÑÑ
пеÑедаÑÑÑÑ Ð² заÑиÑÑованном виде ÑеÑез пÑокÑи, коÑоÑÑе не могÑÑ Ð²Ð¸Ð´ÐµÑÑ, ÑÑо внÑÑÑи, и вÑегда пÑопÑÑкаÑÑ Ð¸Ñ
.
Ðак ÑолÑко обÑÐµÐºÑ WebSocket Ñоздан, Ð¼Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ ÑлÑÑаÑÑ ÐµÐ³Ð¾ ÑобÑÑиÑ. ÐÑ
вÑего 4:
openâ Ñоединение ÑÑÑановлено,messageâ полÑÑÐµÐ½Ñ Ð´Ð°Ð½Ð½Ñе,errorâ оÑибка,closeâ Ñоединение закÑÑÑо.
â¦Ð еÑли Ð¼Ñ Ñ
оÑим оÑпÑавиÑÑ ÑÑо-нибÑдÑ, Ñо вÑзов socket.send(data) ÑÐ´ÐµÐ»Ð°ÐµÑ ÑÑо.
ÐÐ¾Ñ Ð¿ÑимеÑ:
let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
socket.onopen = function(e) {
alert("[open] Соединение ÑÑÑановлено");
alert("ÐÑпÑавлÑем даннÑе на ÑеÑвеÑ");
socket.send("ÐÐµÐ½Ñ Ð·Ð¾Ð²ÑÑ Ðжон");
};
socket.onmessage = function(event) {
alert(`[message] ÐаннÑе полÑÑÐµÐ½Ñ Ñ ÑеÑвеÑа: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
alert(`[close] Соединение закÑÑÑо ÑиÑÑо, код=${event.code} пÑиÑина=${event.reason}`);
} else {
// напÑимеÑ, ÑеÑÐ²ÐµÑ Ñбил пÑоÑеÑÑ Ð¸Ð»Ð¸ ÑеÑÑ Ð½ÐµÐ´Ð¾ÑÑÑпна
// обÑÑно в ÑÑом ÑлÑÑае event.code 1006
alert('[close] Соединение пÑеÑвано');
}
};
socket.onerror = function(error) {
alert(`[error]`);
};
ÐÐ»Ñ Ð´ÐµÐ¼Ð¾Ð½ÑÑÑаÑии еÑÑÑ Ð½ÐµÐ±Ð¾Ð»ÑÑой пÑÐ¸Ð¼ÐµÑ ÑеÑвеÑа server.js, напиÑанного на Node.js, Ð´Ð»Ñ Ð·Ð°Ð¿ÑÑка пÑимеÑа вÑÑе. Ðн оÑвеÑÐ°ÐµÑ Â«ÐÑÐ¸Ð²ÐµÑ Ñ ÑеÑвеÑа, Ðжон», поÑле Ð¾Ð¶Ð¸Ð´Ð°ÐµÑ 5 ÑекÑнд и закÑÑÐ²Ð°ÐµÑ Ñоединение.
Так Ð²Ñ ÑвидиÑе ÑобÑÑÐ¸Ñ open â message â close.
РобÑем-Ñо, вÑÑ, Ð¼Ñ Ñже можем обÑаÑÑÑÑ Ð¿Ð¾ пÑоÑÐ¾ÐºÐ¾Ð»Ñ WebSocket. ÐÑоÑÑо, не Ñак ли?
ТепеÑÑ Ð´Ð°Ð²Ð°Ð¹Ñе поговоÑим более подÑобно.
ÐÑкÑÑÑие веб-ÑокеÑа
Ðогда new WebSocket(url) Ñоздан, он ÑÑÑ Ð¶Ðµ Ñам наÑÐ¸Ð½Ð°ÐµÑ ÑÑÑанавливаÑÑ Ñоединение.
ÐÑаÑзеÑ, пÑи помоÑи ÑпеÑиалÑнÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð², ÑпÑаÑÐ¸Ð²Ð°ÐµÑ ÑеÑвеÑ: Â«Ð¢Ñ Ð¿Ð¾Ð´Ð´ÐµÑживаеÑÑ Websocket?» и еÑли ÑеÑÐ²ÐµÑ Ð¾ÑвеÑÐ°ÐµÑ Â«Ð´Ð°Â», они наÑинаÑÑ ÑабоÑаÑÑ Ð¿Ð¾ пÑоÑÐ¾ÐºÐ¾Ð»Ñ WebSocket, коÑоÑÑй Ñже не ÑвлÑеÑÑÑ HTTP.
ÐÐ¾Ñ Ð¿ÑÐ¸Ð¼ÐµÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² Ð´Ð»Ñ Ð·Ð°Ð¿ÑоÑа, коÑоÑÑй Ð´ÐµÐ»Ð°ÐµÑ new WebSocket("wss://javascript.info/chat").
GET /chat
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Originâ иÑÑоÑник ÑекÑÑей ÑÑÑаниÑÑ (напÑимеÑhttps://javascript.info). ÐбÑÐµÐºÑ WebSocket по Ñвоей пÑиÑоде не завÑзан на ÑекÑÑий иÑÑоÑник. ÐÐµÑ Ð½Ð¸ÐºÐ°ÐºÐ¸Ñ ÑпеÑиалÑнÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð² или дÑÑÐ³Ð¸Ñ Ð¾Ð³ÑаниÑений. СÑаÑÑе ÑеÑвеÑа вÑÑ Ñавно не могÑÑ ÑабоÑаÑÑ Ñ WebSocket, поÑÑÐ¾Ð¼Ñ Ð¿Ñоблем Ñ ÑовмеÑÑимоÑÑÑÑ Ð½ÐµÑ. Ðо заголовокOriginважен, Ñак как он позволÑÐµÑ ÑеÑвеÑÑ ÑеÑаÑÑ, иÑполÑзоваÑÑ Ð»Ð¸ WebSocket Ñ ÑÑим ÑайÑом.Connection: Upgradeâ ÑигнализиÑÑеÑ, ÑÑо ÐºÐ»Ð¸ÐµÐ½Ñ Ñ Ð¾Ñел Ð±Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸ÑÑ Ð¿ÑоÑокол.Upgrade: websocketâ запÑоÑен пÑоÑокол «websocket».Sec-WebSocket-Keyâ ÑлÑÑайнÑй клÑÑ, ÑозданнÑй бÑаÑзеÑом Ð´Ð»Ñ Ð¾Ð±ÐµÑпеÑÐµÐ½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑÑи.Sec-WebSocket-Versionâ веÑÑÐ¸Ñ Ð¿ÑоÑокола WebSocket, ÑекÑÑÐ°Ñ Ð²ÐµÑÑÐ¸Ñ 13.
ÐÑ Ð½Ðµ можем иÑполÑзоваÑÑ XMLHttpRequest или fetch Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñакого HTTP-запÑоÑа, поÑÐ¾Ð¼Ñ ÑÑо JavaScript не позволÑÐµÑ ÑÑÑанавливаÑÑ Ñакие заголовки.
ÐÑли ÑеÑÐ²ÐµÑ ÑоглаÑен пеÑеклÑÑиÑÑÑÑ Ð½Ð° WebSocket, Ñо он должен оÑпÑавиÑÑ Ð² оÑÐ²ÐµÑ ÐºÐ¾Ð´ 101:
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
ÐдеÑÑ Sec-WebSocket-Accept â ÑÑо Sec-WebSocket-Key, пеÑекодиÑованнÑй Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑпеÑиалÑного алгоÑиÑма. ÐÑаÑÐ·ÐµÑ Ð¸ÑполÑзÑÐµÑ ÐµÐ³Ð¾, ÑÑÐ¾Ð±Ñ ÑбедиÑÑÑÑ, ÑÑо оÑÐ²ÐµÑ ÑооÑвеÑÑÑвÑÐµÑ Ð·Ð°Ð¿ÑоÑÑ.
ÐоÑле ÑÑого даннÑе пеÑедаÑÑÑÑ Ð¿Ð¾ пÑоÑÐ¾ÐºÐ¾Ð»Ñ WebSocket, и вÑкоÑе Ð¼Ñ Ñвидим его ÑÑÑÑкÑÑÑÑ («ÑÑеймÑ»). Ð ÑÑо вовÑе не HTTP.
РаÑÑиÑÐµÐ½Ð¸Ñ Ð¸ подпÑоÑоколÑ
ÐогÑÑ Ð±ÑÑÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑнÑе заголовки Sec-WebSocket-Extensions и Sec-WebSocket-Protocol, опиÑÑваÑÑие ÑаÑÑиÑÐµÐ½Ð¸Ñ Ð¸ подпÑоÑоколÑ.
ÐапÑимеÑ:
-
Sec-WebSocket-Extensions: deflate-frameознаÑаеÑ, ÑÑо бÑаÑÐ·ÐµÑ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑжаÑие даннÑÑ . РаÑÑиÑение â ÑÑо ÑÑо-Ñо, ÑвÑзанное Ñ Ð¿ÐµÑедаÑей даннÑÑ , ÑаÑÑиÑÑÑÑее Ñам пÑоÑокол WebSocket. ÐаголовокSec-WebSocket-ExtensionsоÑпÑавлÑеÑÑÑ Ð±ÑаÑзеÑом авÑомаÑиÑеÑки Ñо ÑпиÑком вÑевозможнÑÑ ÑаÑÑиÑений, коÑоÑÑе он поддеÑживаеÑ. -
Sec-WebSocket-Protocol: soap, wampознаÑаеÑ, ÑÑо Ð¼Ñ Ð±Ñдем пеÑедаваÑÑ Ð½Ðµ ÑолÑко пÑоизволÑнÑе даннÑе, но и даннÑе в пÑоÑÐ¾ÐºÐ¾Ð»Ð°Ñ SOAP или WAMP (The WebSocket Application Messaging Protocol" â «пÑоÑокол обмена ÑообÑениÑми WebSocket пÑиложений»). То еÑÑÑ ÑÑÐ¾Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº опиÑÑÐ²Ð°ÐµÑ Ð½Ðµ пеÑедаÑÑ, а ÑоÑÐ¼Ð°Ñ Ð´Ð°Ð½Ð½ÑÑ , коÑоÑÑй Ð¼Ñ ÑобиÑаемÑÑ Ð¸ÑполÑзоваÑÑ. ÐÑиÑиалÑнÑе подпÑоÑÐ¾ÐºÐ¾Ð»Ñ WebSocket ÑегиÑÑÑиÑÑÑÑÑÑ Ð² каÑалоге IANA.ÐÑÐ¾Ñ Ð½ÐµÐ¾Ð±ÑзаÑелÑнÑй заголовок ÑÑавим Ð¼Ñ Ñами, пеÑÐµÐ´Ð°Ð²Ð°Ñ Ð¼Ð°ÑÑив подпÑоÑоколов вÑоÑÑм паÑамеÑÑом
new WebSocket, Ð²Ð¾Ñ Ñак:let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
СеÑÐ²ÐµÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ оÑвеÑиÑÑ Ð¿ÐµÑеÑнем пÑоÑоколов и ÑаÑÑиÑений, коÑоÑÑе он Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑполÑзоваÑÑ.
ÐапÑимеÑ, запÑоÑ:
GET /chat
Host: javascript.info
Upgrade: websocket
Connection: Upgrade
Origin: https://javascript.info
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap, wamp
ÐÑвеÑ:
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap
ÐдеÑÑ ÑеÑÐ²ÐµÑ Ð¾ÑвеÑаеÑ, ÑÑо поддеÑÐ¶Ð¸Ð²Ð°ÐµÑ ÑаÑÑиÑение â deflate-frame и Ð¼Ð¾Ð¶ÐµÑ Ð¸ÑполÑзоваÑÑ ÑолÑко пÑоÑокол SOAP из вÑего ÑпиÑка запÑоÑеннÑÑ Ð¿Ð¾Ð´Ð¿ÑоÑоколов.
ÐеÑедаÑа даннÑÑ
ÐоÑок даннÑÑ Ð² WebSocket ÑоÑÑÐ¾Ð¸Ñ Ð¸Ð· «ÑÑеймов», ÑÑагменÑов даннÑÑ , коÑоÑÑе могÑÑ Ð±ÑÑÑ Ð¾ÑпÑÐ°Ð²Ð»ÐµÐ½Ñ Ð»Ñбой ÑÑоÑоной, и коÑоÑÑе могÑÑ Ð±ÑÑÑ ÑледÑÑÑÐ¸Ñ Ð²Ð¸Ð´Ð¾Ð²:
- «ÑекÑÑовÑе ÑÑеймÑ» â ÑодеÑÐ¶Ð°Ñ ÑекÑÑовÑе даннÑе, коÑоÑÑе ÑÑоÑÐ¾Ð½Ñ Ð¾ÑпÑавлÑÑÑ Ð´ÑÑг дÑÑгÑ.
- «бинаÑнÑе ÑÑеймÑ» â ÑодеÑÐ¶Ð°Ñ Ð±Ð¸Ð½Ð°ÑнÑе даннÑе, коÑоÑÑе ÑÑоÑÐ¾Ð½Ñ Ð¾ÑпÑавлÑÑÑ Ð´ÑÑг дÑÑгÑ.
- «пинг-понг ÑÑеймÑ» иÑполÑзÑеÑÑÑ Ð´Ð»Ñ Ð¿ÑовеÑки ÑоединениÑ; оÑпÑавлÑеÑÑÑ Ñ ÑеÑвеÑа, бÑаÑÐ·ÐµÑ ÑеагиÑÑÐµÑ Ð½Ð° Ð½Ð¸Ñ Ð°Ð²ÑомаÑиÑеÑки.
- Ñакже еÑÑÑ Â«ÑÑейм закÑÑÑÐ¸Ñ ÑоединениÑ» и некоÑоÑÑе дÑÑгие ÑлÑжебнÑе ÑÑеймÑ.
РбÑаÑзеÑе Ð¼Ñ Ð½Ð°Ð¿ÑÑмÑÑ ÑабоÑаем ÑолÑко Ñ ÑекÑÑовÑми и бинаÑнÑми ÑÑеймами.
ÐеÑод WebSocket .send() Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑпÑавлÑÑÑ Ð¸ ÑекÑÑовÑе, и бинаÑнÑе даннÑе.
ÐÑзов socket.send(body) пÑÐ¸Ð½Ð¸Ð¼Ð°ÐµÑ body в виде ÑÑÑоки или лÑбом бинаÑном ÑоÑмаÑе вклÑÑÐ°Ñ Blob, ArrayBuffer и дÑÑгие. ÐополниÑелÑнÑÑ
наÑÑÑоек не ÑÑебÑеÑÑÑ, пÑоÑÑо оÑпÑавлÑем в лÑбом ÑоÑмаÑе.
ÐÑи полÑÑении даннÑÑ
, ÑекÑÑ Ð²Ñегда поÑÑÑÐ¿Ð°ÐµÑ Ð² виде ÑÑÑоки. Ð Ð´Ð»Ñ Ð±Ð¸Ð½Ð°ÑнÑÑ
даннÑÑ
Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ вÑбÑаÑÑ Ð¾Ð´Ð¸Ð½ из двÑÑ
ÑоÑмаÑов: Blob или ArrayBuffer.
ÐÑо задаÑÑÑÑ ÑвойÑÑвом socket.binaryType, по ÑмолÑÐ°Ð½Ð¸Ñ Ð¾Ð½Ð¾ Ñавно "blob", Ñак ÑÑо бинаÑнÑе даннÑе поÑÑÑпаÑÑ Ð² виде Blob-обÑекÑов.
Blob â ÑÑо вÑÑокоÑÑовневÑй бинаÑнÑй обÑекÑ, он напÑÑмÑÑ Ð¸Ð½ÑегÑиÑÑеÑÑÑ Ñ <a>, <img> и дÑÑгими Ñегами, Ñак ÑÑо ÑÑо вполне Ñдобное знаÑение по ÑмолÑаниÑ. Ðо Ð´Ð»Ñ Ð¾Ð±ÑабоÑки даннÑÑ
, еÑли ÑÑебÑеÑÑÑ Ð´Ð¾ÑÑÑп к оÑделÑнÑм байÑам, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ измениÑÑ ÐµÐ³Ð¾ на "arraybuffer":
socket.binaryType = "arraybuffer";
socket.onmessage = (event) => {
// event.data ÑвлÑеÑÑÑ ÑÑÑокой (еÑли ÑекÑÑ) или arraybuffer (еÑли двоиÑнÑе даннÑе)
};
ÐгÑаниÑение ÑкоÑоÑÑи
ÐÑедÑÑавим, ÑÑо наÑе пÑиложение генеÑиÑÑÐµÑ Ð¼Ð½Ð¾Ð³Ð¾ даннÑÑ Ð´Ð»Ñ Ð¾ÑпÑавки. Ðо Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾Ðµ Ñоединение, возможно, он в инÑеÑнеÑе Ñ Ð¼Ð¾Ð±Ð¸Ð»Ñного ÑелеÑона и не из гоÑода.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ вÑзÑваÑÑ socket.send(data) Ñнова и Ñнова. Ðо даннÑе бÑдÑÑ Ð±ÑÑеÑÐ¸Ð·Ð¾Ð²Ð°Ð½Ñ (ÑоÑ
ÑаненÑ) в памÑÑи и оÑпÑÐ°Ð²Ð»ÐµÐ½Ñ Ð»Ð¸ÑÑ Ñ Ñой ÑкоÑоÑÑÑÑ, коÑоÑÑÑ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÐµÑ ÑеÑÑ.
СвойÑÑво socket.bufferedAmount Ñ
ÑÐ°Ð½Ð¸Ñ ÐºÐ¾Ð»Ð¸ÑеÑÑво Ð±Ð°Ð¹Ñ Ð±ÑÑеÑизованнÑÑ
даннÑÑ
на ÑекÑÑий моменÑ, ожидаÑÑиÑ
оÑпÑавки по ÑеÑи.
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ изÑÑиÑÑ ÐµÐ³Ð¾, ÑÑÐ¾Ð±Ñ ÑвидеÑÑ, дейÑÑвиÑелÑно ли ÑÐ¾ÐºÐµÑ Ð´Ð¾ÑÑÑпен Ð´Ð»Ñ Ð¿ÐµÑедаÑи.
// каждÑе 100Ð¼Ñ Ð¿ÑовеÑиÑÑ ÑÐ¾ÐºÐµÑ Ð¸ оÑпÑавиÑÑ Ð±Ð¾Ð»ÑÑе даннÑÑ
,
// ÑолÑко еÑли вÑе ÑекÑÑие оÑоÑланÑ
setInterval(() => {
if (socket.bufferedAmount == 0) {
socket.send(moreData());
}
}, 100);
ÐакÑÑÑие подклÑÑениÑ
ÐбÑÑно, когда ÑÑоÑона Ñ Ð¾ÑÐµÑ Ð·Ð°ÐºÑÑÑÑ Ñоединение (бÑаÑÐ·ÐµÑ Ð¸ ÑеÑÐ²ÐµÑ Ð¸Ð¼ÐµÑÑ ÑавнÑе пÑава), они оÑпÑавлÑÑÑ Â«ÑÑейм закÑÑÑÐ¸Ñ ÑоединениÑ» Ñ ÐºÐ¾Ð´Ð¾Ð¼ закÑÑÑÐ¸Ñ Ð¸ ÑказÑваÑÑ Ð¿ÑиÑÐ¸Ð½Ñ Ð² виде ÑекÑÑа.
ÐеÑод Ð´Ð»Ñ ÑÑого:
socket.close([code], [reason]);
codeâ ÑпеÑиалÑнÑй WebSocket-код закÑÑÑÐ¸Ñ (не обÑзаÑелен).reasonâ ÑÑÑока Ñ Ð¾Ð¿Ð¸Ñанием пÑиÑÐ¸Ð½Ñ Ð·Ð°ÐºÑÑÑÐ¸Ñ (не обÑзаÑелÑна).
ÐаÑем пÑоÑÐ¸Ð²Ð¾Ð¿Ð¾Ð»Ð¾Ð¶Ð½Ð°Ñ ÑÑоÑона в обÑабоÑÑике ÑобÑÑÐ¸Ñ close полÑÑÐ¸Ñ Ð¸ код code и пÑиÑÐ¸Ð½Ñ reason, напÑимеÑ:
// закÑÑваÑÑÐ°Ñ ÑÑоÑона:
socket.close(1000, "ÑабоÑа законÑена");
// дÑÑÐ³Ð°Ñ ÑÑоÑона:
socket.onclose = event => {
// event.code === 1000
// event.reason === "ÑабоÑа законÑена"
// event.wasClean === true (закÑÑÑо ÑиÑÑо)
};
code â ÑÑо не лÑбое ÑиÑло, а ÑпеÑиалÑнÑй код закÑÑÑÐ¸Ñ WebSocket.
Ðаиболее ÑаÑпÑоÑÑÑанÑннÑе знаÑениÑ:
1000â по ÑмолÑаниÑ, ноÑмалÑное закÑÑÑие,1006â невозможно ÑÑÑановиÑÑ Ñакой код вÑÑÑнÑÑ, ÑказÑваеÑ, ÑÑо Ñоединение бÑло поÑеÑÑно (Ð½ÐµÑ ÑÑейма закÑÑÑиÑ).
ÐÑÑÑ Ð¸ дÑÑгие кодÑ:
1001â ÑÑоÑона оÑклÑÑилаÑÑ, напÑÐ¸Ð¼ÐµÑ ÑеÑÐ²ÐµÑ Ð²ÑклÑÑен или полÑзоваÑÐµÐ»Ñ Ð¿Ð¾ÐºÐ¸Ð½Ñл ÑÑÑаниÑÑ,1009â ÑообÑение ÑлиÑком болÑÑое Ð´Ð»Ñ Ð¾Ð±ÑабоÑки,1011â непÑÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ Ð¾Ñибка на ÑеÑвеÑе,- â¦Ð¸ Ñак далее.
ÐолнÑй ÑпиÑок Ð½Ð°Ñ Ð¾Ð´Ð¸ÑÑÑ Ð² RFC6455, §7.4.1.
ÐÐ¾Ð´Ñ WebSocket Ñем-Ñо поÑ
ожи на ÐºÐ¾Ð´Ñ HTTP, но они ÑазнÑе. Ð ÑаÑÑноÑÑи, лÑбÑе ÐºÐ¾Ð´Ñ Ð¼ÐµÐ½ÑÑе 1000 заÑезеÑвиÑованÑ. ÐÑли Ð¼Ñ Ð¿Ð¾Ð¿ÑÑаемÑÑ ÑÑÑановиÑÑ Ñакой код, Ñо полÑÑим оÑибкÑ.
// в ÑлÑÑае, еÑли Ñоединение ÑбÑоÑено
socket.onclose = event => {
// event.code === 1006
// event.reason === ""
// event.wasClean === false (Ð½ÐµÑ Ð·Ð°ÐºÑÑваÑÑего кадÑа)
};
СоÑÑоÑние ÑоединениÑ
ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑÑиÑÑ ÑоÑÑоÑние ÑоединениÑ, ÑÑÑеÑÑвÑÐµÑ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑное ÑвойÑÑво socket.readyState Ñо знаÑениÑми:
0â «CONNECTING»: Ñоединение еÑÑ Ð½Ðµ ÑÑÑановлено,1â «OPEN»: обмен даннÑми,2â «CLOSING»: Ñоединение закÑÑваеÑÑÑ,3â «CLOSED»: Ñоединение закÑÑÑо.
ÐÑÐ¸Ð¼ÐµÑ ÑаÑа
ÐавайÑе ÑаÑÑмоÑÑим пÑÐ¸Ð¼ÐµÑ ÑаÑа Ñ Ð¸ÑполÑзованием WebSocket API и модÑÐ»Ñ WebSocket ÑеÑвеÑа Node.js https://github.com/websockets/ws. ÐÑновное внимание мÑ, конеÑно, Ñделим клиенÑÑкой ÑаÑÑи, но и ÑеÑвеÑÐ½Ð°Ñ Ð²ÐµÑÑма пÑоÑÑа.
HTML: нам нÑжна ÑоÑма <form> Ð´Ð»Ñ Ð¾ÑпÑавки даннÑÑ
и <div> Ð´Ð»Ñ Ð¾ÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ ÑообÑений:
<!-- ÑоÑма ÑообÑений -->
<form name="publish">
<input type="text" name="message">
<input type="submit" value="ÐÑпÑавиÑÑ">
</form>
<!-- div Ñ ÑообÑениÑми -->
<div id="messages"></div>
ÐÑ JavaScript Ð¼Ñ Ñ Ð¾Ñим 3 веÑи:
- ÐÑкÑÑÑÑ Ñоединение.
- ÐÑи оÑпÑавке ÑоÑÐ¼Ñ Ð¿Ð¾Ð»ÑзоваÑелем â вÑзваÑÑ
socket.send(message)Ð´Ð»Ñ ÑообÑениÑ. - ÐÑи полÑÑении вÑ
одÑÑего ÑообÑÐµÐ½Ð¸Ñ â добавиÑÑ ÐµÐ³Ð¾ в
div#messages.
ÐÐ¾Ñ ÐºÐ¾Ð´:
let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws");
// оÑпÑавка ÑообÑÐµÐ½Ð¸Ñ Ð¸Ð· ÑоÑмÑ
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
socket.send(outgoingMessage);
return false;
};
// полÑÑение ÑообÑÐµÐ½Ð¸Ñ - оÑобÑазиÑÑ Ð´Ð°Ð½Ð½Ñе в div#messages
socket.onmessage = function(event) {
let message = event.data;
let messageElem = document.createElement('div');
messageElem.textContent = message;
document.getElementById('messages').prepend(messageElem);
}
СеÑвеÑнÑй код вÑÑ Ð¾Ð´Ð¸Ñ Ð·Ð° Ñамки ÑÑой главÑ. ÐдеÑÑ Ð¼Ñ Ð±Ñдем иÑполÑзоваÑÑ Node.js, но Ð²Ñ Ð½Ðµ обÑÐ·Ð°Ð½Ñ ÑÑо делаÑÑ. ÐÑÑгие плаÑÑоÑÐ¼Ñ Ñакже поддеÑживаÑÑ ÑÑедÑÑва Ð´Ð»Ñ ÑабоÑÑ Ñ WebSocket.
СеÑвеÑнÑй алгоÑиÑм дейÑÑвий бÑÐ´ÐµÑ Ñаким:
- СоздаÑÑ
clients = new Set()â Ð½Ð°Ð±Ð¾Ñ ÑокеÑов. - ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ пÑинÑÑого веб-ÑокеÑа â добавиÑÑ ÐµÐ³Ð¾ в набоÑ
clients.add(socket)и поÑÑавиÑÑ ÐµÐ¼Ñ Ð¾Ð±ÑабоÑÑик ÑобÑÑиÑmessageÐ´Ð»Ñ Ð¿ÑиÑма ÑообÑений. - Ðогда ÑообÑение полÑÑено: пеÑебÑаÑÑ ÐºÐ»Ð¸ÐµÐ½Ñов
clientsи оÑпÑавиÑÑ ÐµÐ³Ð¾ вÑем. - Ðогда подклÑÑение закÑÑÑо:
clients.delete(socket).
const ws = new require('ws');
const wss = new ws.Server({noServer: true});
const clients = new Set();
http.createServer((req, res) => {
// в ÑеалÑном пÑоекÑе здеÑÑ Ð¼Ð¾Ð¶ÐµÑ Ñакже бÑÑÑ ÐºÐ¾Ð´ Ð´Ð»Ñ Ð¾Ð±ÑабоÑки оÑлиÑнÑÑ
Ð¾Ñ websoÑket-запÑоÑов
// здеÑÑ Ð¼Ñ ÑабоÑаем Ñ ÐºÐ°Ð¶Ð´Ñм запÑоÑом как Ñ Ð²ÐµÐ±-ÑокеÑом
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onSocketConnect);
});
function onSocketConnect(ws) {
clients.add(ws);
ws.on('message', function(message) {
message = message.slice(0, 50); // макÑималÑнÑй ÑÐ°Ð·Ð¼ÐµÑ ÑообÑÐµÐ½Ð¸Ñ 50
for(let client of clients) {
client.send(message);
}
});
ws.on('close', function() {
clients.delete(ws);
});
}
ÐÐ¾Ñ ÑабоÑий пÑимеÑ:
ÐÑ Ñакже можеÑе ÑкаÑаÑÑ ÐµÐ³Ð¾ (веÑÑ
нÑÑ Ð¿ÑÐ°Ð²Ð°Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° в иÑÑейме) и запÑÑÑиÑÑ Ð»Ð¾ÐºÐ°Ð»Ñно. ТолÑко не забÑдÑÑе ÑÑÑановиÑÑ Node.js и вÑполниÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ npm install ws до запÑÑка.
ÐÑого
WebSocket â ÑÑо ÑовÑеменнÑй ÑпоÑоб имеÑÑ Ð¿Ð¾ÑÑоÑнное Ñоединение Ð¼ÐµÐ¶Ð´Ñ Ð±ÑаÑзеÑом и ÑеÑвеÑом.
- ÐÐµÑ Ð¾Ð³ÑаниÑений, ÑвÑзаннÑÑ Ñ ÐºÑоÑÑ-доменнÑми запÑоÑами.
- ÐмеÑÑ Ñ Ð¾ÑоÑÑÑ Ð¿Ð¾Ð´Ð´ÐµÑÐ¶ÐºÑ Ð±ÑаÑзеÑами.
- ÐогÑÑ Ð¾ÑпÑавлÑÑÑ/полÑÑаÑÑ ÐºÐ°Ðº ÑÑÑоки, Ñак и бинаÑнÑе даннÑе.
API пÑоÑÑ.
ÐеÑодÑ:
socket.send(data),socket.close([code], [reason]).
СобÑÑиÑ:
open,message,error,close.
WebSocket Ñам по Ñебе не ÑодеÑÐ¶Ð¸Ñ Ñакие ÑÑнкÑии, как пеÑеподклÑÑение пÑи обÑÑве ÑоединениÑ, аÑÑенÑиÑикаÑÐ¸Ñ Ð¿Ð¾Ð»ÑзоваÑелей и дÑÑгие Ð¼ÐµÑ Ð°Ð½Ð¸Ð·Ð¼Ñ Ð²ÑÑокого ÑÑовнÑ. ÐÐ»Ñ ÑÑого еÑÑÑ ÐºÐ»Ð¸ÐµÐ½ÑÑкие и ÑеÑвеÑнÑе библиоÑеки, а Ñакже можно ÑеализоваÑÑ ÑÑо вÑÑÑнÑÑ.
Ðногда, ÑÑÐ¾Ð±Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ WebSocket к Ñже ÑÑÑеÑÑвÑÑÑÐµÐ¼Ñ Ð¿ÑоекÑÑ, WebSocket-ÑеÑÐ²ÐµÑ Ð·Ð°Ð¿ÑÑкаÑÑ Ð¿Ð°ÑаллелÑно Ñ Ð¾ÑновнÑм ÑеÑвеÑом. Ðни ÑовмеÑÑно иÑполÑзÑÑÑ Ð¾Ð´Ð½Ñ Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð½ÑÑ
. ÐапÑоÑÑ Ðº WebSocket оÑпÑавлÑÑÑÑÑ Ð½Ð° wss://ws.site.com â поддомен, коÑоÑÑй ведÑÑ Ðº WebSocket-ÑеÑвеÑÑ, в Ñо вÑÐµÐ¼Ñ ÐºÐ°Ðº https://site.com ведÑÑ Ð½Ð° оÑновной HTTP-ÑеÑвеÑ.
ÐонеÑно, Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ñ Ð¸ дÑÑгие пÑÑи инÑегÑаÑии.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)