RFC 6455 spetsifikatsiyasida tasvirlangan WebSocket protokoli brauzer va server oârtasida doimiy ulanish orqali maâlumot almashinuv imkonini beradi. Maâlumotlar ulanishni uzmasdan va qoâshimcha HTTP-soârovlarsiz âpaketlarâ sifatida ikki tomonga ham uzatilishi mumkin.
WebSocket doimiy maâlumot almashuvni talab qiladigan xizmatlar uchun ayniqsa ajoyib, masalan onlayn oâyinlar, real-time savdo tizimlari va hokazo.
Oddiy misol
Websocket ulanishini ochish uchun urlâda maxsus ws protokolidan foydalanib new WebSocket yaratishimiz kerak:
let socket = new WebSocket("ws://javascript.info");
Shifrlangan wss:// protokoli ham mavjud. Bu websocketâlar uchun HTTPS kabi.
wss:// ni afzal koâringwss:// protokoli nafaqat shifrlangan, balki yanada ishonchliroq.
Buning sababi ws:// maâlumotlari shifrlanmagan, har qanday vositachi uchun koârinadi. Eski proksi serverlar WebSocket haqida bilmaydi, ular âgâalatiâ headerâlarni koârib, ulanishni toâxtatishi mumkin.
Boshqa tomondan, wss:// â bu TLS ustidagi WebSocket (xuddi HTTPS ning HTTP ustidagi TLS kabi), transport xavfsizlik qatlami maâlumotlarni yuboruvchida shifrlaydi va qabul qiluvchida ochadi. Shuning uchun maâlumot paketlari proksilar orqali shifrlangan holda oâtadi. Ular ichida nima borligini koâra olmaydi va ularni oâtkazib yuboradi.
Socket yaratilgandan keyin, uning eventâlarini tinglashimiz kerak. Jami 4 ta event bor:
openâ ulanish oârnatildi,messageâ maâlumot qabul qilindi,errorâ websocket xatosi,closeâ ulanish yopildi.
â¦Va agar biror narsa yubormoqchi boâlsak, socket.send(data) buni amalga oshiradi.
Mana misol:
let socket = new WebSocket("wss://javascript.info/article/websocket/demo/hello");
socket.onopen = function(e) {
alert("[open] Ulanish o'rnatildi");
alert("Serverga yuborish");
socket.send("Mening ismim John");
};
socket.onmessage = function(event) {
alert(`[message] Serverdan ma'lumot qabul qilindi: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
alert(`[close] Ulanish toza yopildi, kod=${event.code} sabab=${event.reason}`);
} else {
// masalan server jarayoni o'ldirilgan yoki tarmoq uzilgan
// event.code odatda bu holatda 1006 bo'ladi
alert('[close] Ulanish uzildi');
}
};
socket.onerror = function(error) {
alert(`[error] ${error.message}`);
};
Demo maqsadida yuqoridagi misol uchun Node.js da yozilgan kichik server server.js ishlamoqda. U âHello from server, Johnâ deb javob beradi, keyin 5 soniya kutadi va ulanishni yopadi.
Shunday qilib, siz open â message â close eventâlarini koârasiz.
Aslida shu, biz allaqachon WebSocket bilan gaplasha olamiz. Juda oddiy, shunday emasmi?
Endi chuqurroq gaplashaylik.
Websocket ochish
new WebSocket(url) yaratilganda, u darhol ulanishni boshlaydi.
Ulanish davomida brauzer (headerâlar yordamida) serverdan soâraydi: âSiz Websocketâni qoâllab-quvvatlaysizmi?â Va agar server âhaâ deb javob bersa, suhbat WebSocket protokolida davom etadi, bu umuman HTTP emas.
Mana new WebSocket("wss://javascript.info/chat") tomonidan qilingan soârov uchun brauzer headerâlarining misoli.
GET /chat
Host: javascript.info
Origin: https://javascript.info
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
Sec-WebSocket-Version: 13
Originâ mijoz sahifasining originâi, masalanhttps://javascript.info. WebSocket obyektlari oâz tabiatiga koâra cross-origin. Maxsus headerâlar yoki boshqa cheklovlar yoâq. Eski serverlar baribir WebSocket bilan ishlay olmaydi, shuning uchun moslashuv muammolari yoâq. LekinOriginheader muhim, chunki u serverga ushbu veb-sayt bilan WebSocket gaplashish yoki yoâqligini hal qilish imkonini beradi.Connection: Upgradeâ mijoz protokolni oâzgartirmoqchi ekanligini bildiradi.Upgrade: websocketâ soâralgan protokol âwebsocketâ.Sec-WebSocket-Keyâ xavfsizlik uchun brauzer tomonidan yaratilgan tasodifiy kalit.Sec-WebSocket-Versionâ WebSocket protokol versiyasi, 13 joriy versiya.
Bunday HTTP-soârovni qilish uchun XMLHttpRequest yoki fetch dan foydalana olmaymiz, chunki JavaScriptâga bu headerâlarni oârnatishga ruxsat berilmagan.
Agar server WebSocketâga oâtishga rozi boâlsa, u 101 javob kodini yuborishi kerak:
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Bu yerda Sec-WebSocket-Accept â bu maxsus algoritm yordamida qayta kodlangan Sec-WebSocket-Key. Brauzer buni javob soârovga mos kelishiga ishonch hosil qilish uchun ishlatadi.
Shundan soâng maâlumotlar WebSocket protokoli yordamida uzatiladi, tez orada uning tuzilishini (âframeâlarâ) koâramiz. Va bu umuman HTTP emas.
Kengaytmalar va subprotokolâlar
Sec-WebSocket-Extensions va Sec-WebSocket-Protocol kengaytmalar va subprotokolâlarni tasvirlaydigan qoâshimcha headerâlar boâlishi mumkin.
Masalan:
-
Sec-WebSocket-Extensions: deflate-framebrauzer maâlumot siqilishini qoâllab-quvvatlashini bildiradi. Kengaytma â bu maâlumot uzatish bilan bogâliq narsa, WebSocket protokolini kengaytiradigan funksionallik.Sec-WebSocket-Extensionsheaderâi brauzer tomonidan qoâllab-quvvatlaydigan barcha kengaytmalar roâyxati bilan avtomatik yuboriladi. -
Sec-WebSocket-Protocol: soap, wampbiz faqat har qanday maâlumot emas, balki SOAP yoki WAMP (âThe WebSocket Application Messaging Protocolâ) protokollaridagi maâlumotlarni uzatmoqchi ekanligimizni bildiradi. WebSocket subprotokolâlari IANA katalogida roâyxatga olingan. Shunday qilib, bu header biz foydalanadigan maâlumot formatlarini tasvirlaydi.Bu ixtiyoriy header
new WebSocketning ikkinchi parametri yordamida oârnatiladi. Bu subprotokolâlar massivi, masalan agar biz SOAP yoki WAMP dan foydalanmoqchi boâlsak:let socket = new WebSocket("wss://javascript.info/chat", ["soap", "wamp"]);
Server foydalanishga rozi boâlgan protokol va kengaytmalar roâyxati bilan javob berishi kerak.
Masalan, soârov:
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
Javob:
101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: hsBlbuDTkk24srzEOTBUlZAlC2g=
Sec-WebSocket-Extensions: deflate-frame
Sec-WebSocket-Protocol: soap
Bu yerda server âdeflate-frameâ kengaytmasini qoâllab-quvvatlashini va soâralgan subprotokolâlardan faqat SOAPâni javob berdi.
Maâlumot uzatish
WebSocket aloqasi "frameâlar"dan iborat â bu ikki tomondan yuborilishi mumkin boâlgan maâlumot qismlari va bir nechta turga ega boâlishi mumkin:
- âtext frameâlarâ â tomonlar bir-biriga yuboradigan matn maâlumotlarini oâz ichiga oladi.
- âbinary data frameâlarâ â tomonlar bir-biriga yuboradigan ikkilik maâlumotlarni oâz ichiga oladi.
- âping/pong frameâlarâ ulanishni tekshirish uchun ishlatiladi, serverdan yuboriladi, brauzer ularga avtomatik javob beradi.
- âconnection close frameâ va bir nechta boshqa xizmat frameâlari ham bor.
Brauzerde biz faqat matn yoki ikkilik frameâlar bilan bevosita ishlaymiz.
WebSocket .send() metodi matn yoki ikkilik maâlumotlarni yuborishi mumkin.
socket.send(body) chaqiruvi body ni string yoki ikkilik formatda, jumladan Blob, ArrayBuffer va boshqalarda qabul qiladi. Hech qanday sozlash kerak emas: shunchaki har qanday formatda yuboring.
Maâlumot qabul qilganimizda, matn har doim string sifatida keladi. Ikkilik maâlumotlar uchun Blob va ArrayBuffer formatlari oârtasida tanlov qilishimiz mumkin.
Bu socket.binaryType xususiyati bilan oârnatiladi, sukut boâyicha u "blob", shuning uchun ikkilik maâlumotlar Blob obyektlari sifatida keladi.
Blob â bu yuqori darajali ikkilik obyekt, u <a>, <img> va boshqa teglar bilan bevosita integratsiyalashadi, shuning uchun bu mantiqiy standart. Lekin ikkilik ishlov berish uchun, alohida maâlumot baytlariga kirish uchun uni "arraybuffer" ga oâzgartirishimiz mumkin:
socket.binaryType = "arraybuffer";
socket.onmessage = (event) => {
// event.data string (agar matn bo'lsa) yoki arraybuffer (agar ikkilik bo'lsa)
};
Tezlik cheklash
Tasavvur qiling, bizning ilovamiz yuborish uchun juda koâp maâlumot ishlab chiqarmoqda. Lekin foydalanuvchining sekin tarmoq ulanishi bor, ehtimol mobil internetda, shahardan tashqarida.
Biz socket.send(data) ni qayta-qayta chaqirishimiz mumkin. Lekin maâlumotlar xotirada buferlashtiriladi (saqlanadi) va faqat tarmoq tezligi ruxsat bergani qadar tez yuboriladi.
socket.bufferedAmount xususiyati hozirgi paytda tarmoq orqali yuborilishini kutayotgan necha bayt buferlashtirilganini saqlaydi.
Biz socket haqiqatan ham uzatish uchun mavjudligini koârish uchun uni tekshirishimiz mumkin.
// har 100ms da socket'ni tekshiring va ko'proq ma'lumot yuboring
// faqat mavjud ma'lumotlar yuborilgan bo'lsa
setInterval(() => {
if (socket.bufferedAmount == 0) {
socket.send(moreData());
}
}, 100);
Ulanishni yopish
Odatda, tomon ulanishni yopmoqchi boâlganda (brauzer ham, server ham teng huquqlarga ega), ular raqamli kod va matnli sabab bilan âconnection close frameâ yuboradi.
Buning uchun metod:
socket.close([code], [reason]);
codeâ maxsus WebSocket yopish kodi (ixtiyoriy)reasonâ yopish sababini tasvirlaydigan string (ixtiyoriy)
Keyin boshqa tomon close event handlerâida kod va sababni oladi, masalan:
// yopuvchi tomon:
socket.close(1000, "Ish tugallandi");
// boshqa tomon
socket.onclose = event => {
// event.code === 1000
// event.reason === "Ish tugallandi"
// event.wasClean === true (toza yopish)
};
Eng keng tarqalgan kod qiymatlari:
1000â standart, oddiy yopish (agarcodeberilmagan boâlsa ishlatiladi),1006â bunday kodni qoâlda oârnatishning yoâli yoâq, ulanish yoâqolganini bildiradi (yopish frameâi yoâq).
Boshqa kodlar ham bor:
1001â tomon ketmoqda, masalan server oâchirilyapti, yoki brauzer sahifani tark etmoqda,1009â xabar qayta ishlash uchun juda katta,1011â serverda kutilmagan xato,- â¦va hokazo.
Toâliq roâyxatni RFC6455, §7.4.1 da topishingiz mumkin.
WebSocket kodlari HTTP kodlariga oâxshash, lekin farqli. Xususan, 1000 dan kichik har qanday kodlar zaxiralangan, bunday kodni oârnatishga harakat qilsak xato boâladi.
// ulanish uzilgan holatda
socket.onclose = event => {
// event.code === 1006
// event.reason === ""
// event.wasClean === false (yopish frame'i yo'q)
};
Ulanish holati
Ulanish holatini olish uchun qiymatlar bilan socket.readyState xususiyati ham bor:
0â âCONNECTINGâ: ulanish hali oârnatilmagan,1â âOPENâ: muloqot qilmoqda,2â âCLOSINGâ: ulanish yopilmoqda,3â âCLOSEDâ: ulanish yopilgan.
Chat misoli
Brauzer WebSocket API va Node.js WebSocket moduli https://github.com/websockets/ws dan foydalangan holda chat misolini koârib chiqaylik. Biz asosiy eâtiborni mijoz tomoniga qaratamiz, lekin server ham oddiy.
HTML: xabar yuborish uchun <form> va keluvchi xabarlar uchun <div> kerak:
<!-- xabar shakli -->
<form name="publish">
<input type="text" name="message">
<input type="submit" value="Yuborish">
</form>
<!-- xabarlar bilan div -->
<div id="messages"></div>
JavaScriptâdan biz uchta narsa istayamiz:
- Ulanishni ochish.
- Shakl yuborilib-- xabar uchun
socket.send(message). - Keluvchi xabarda â uni
div#messagesga qoâshish.
Mana kod:
let socket = new WebSocket("wss://javascript.info/article/websocket/chat/ws");
// shakldan xabar yuborish
document.forms.publish.onsubmit = function() {
let outgoingMessage = this.message.value;
socket.send(outgoingMessage);
return false;
};
// xabar qabul qilindi - xabarni div#messages da ko'rsatish
socket.onmessage = function(event) {
let message = event.data;
let messageElem = document.createElement('div');
messageElem.textContent = message;
document.getElementById('messages').prepend(messageElem);
}
Server-side kodi bizning doiramizdan biroz tashqarida. Bu yerda biz Node.js dan foydalanamiz, lekin shart emas. Boshqa platformalar ham WebSocket bilan ishlashning oâz vositalariga ega.
Server-side algoritmi quyidagicha boâladi:
clients = new Set()yaratish â socketlar toâplami.- Har bir qabul qilingan websocket uchun uni toâplamga qoâshing
clients.add(socket)va xabarlarini olish uchunmessageevent listener oârnating. - Xabar qabul qilinganda: mijozlar boâylab takrorlang va hammaga yuboring.
- Ulanish yopilganda:
clients.delete(socket).
const ws = new require('ws');
const wss = new ws.Server({noServer: true});
const clients = new Set();
http.createServer((req, res) => {
// bu yerda biz faqat websocket ulanishlarini boshqaramiz
// haqiqiy loyihada bizda websocket bo'lmagan so'rovlarni boshqarish uchun boshqa kodlar bo'lar edi
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); // maksimal xabar uzunligi 50 bo'ladi
for(let client of clients) {
client.send(message);
}
});
ws.on('close', function() {
clients.delete(ws);
});
}
Mana ishlaydigan misol:
Siz uni yuklab olishingiz (iframeâdagi yuqori-oâng tugma) va mahalliy ishga tushirishingiz ham mumkin. Faqat ishga tushirishdan oldin Node.js va npm install ws oârnatishni unutmang.
Xulosa
WebSocket doimiy brauzer-server ulanishiga ega boâlishning zamonaviy usuli.
- WebSocketâlar cross-origin cheklovlariga ega emas.
- Ular brauzerlarda yaxshi qoâllab-quvvatlanadi.
- String va ikkilik maâlumotlarni yuborish/qabul qilish mumkin.
API oddiy.
Metodlar:
socket.send(data),socket.close([code], [reason]).
Eventâlar:
open,message,error,close.
WebSocket oâzi qayta ulanish, autentifikatsiya va boshqa koâplab yuqori darajadagi mexanizmlarni oâz ichiga olmaydi. Shuning uchun buning uchun mijoz/server kutubxonalari mavjud va bu imkoniyatlarni qoâlda ham amalga oshirish mumkin.
Baâzan WebSocketâni mavjud loyihaga integratsiya qilish uchun odamlar WebSocket serverni asosiy HTTP-server bilan parallel ishga tushiradilar va ular bitta maâlumotlar bazasini baham koâradiadi. WebSocketâga soârovlar WebSocket serverga olib boradigan wss://ws.site.com subdomainidan foydalanadi, https://site.com esa asosiy HTTP-serverga boradi.
Albatta, integratsiyaning boshqa usullari ham mumkin.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)