IlmHamroh
JavaScript Full-stack/29-qism. Backend integratsiyalar: fayl, to'lov, bot, realtime40/69-dars15 daqiqa
Mundarija (31)

Socket.IO: hodisalar, xonalar, ack va SSE bilan o'lchov

Qisqacha: Socket.IO — WebSocket ustidagi qatlam: nomli hodisalar (emit/on), javobni kutish (ack), foydalanuvchilarni xonalarga (rooms) guruhlash, namespace'lar, middleware bilan auth, avtomatik qayta ulanish va WebSocket ishlamasa HTTP long polling'ga qaytish. U o'z protokoliga ega — oddiy WebSocket mijoz unga ulana olmaydi. Bizning o'lchovimizda Socket.IO, ws va SSE kechikishi bir necha millisekund ichida, ishga tushirishdan ishga tushirishga o'rni almashib turdi: tanlov tezlik bilan emas, kerakli imkoniyatlar bilan qilinadi.

Bu darsda

  • Socket.IO ichida WebSocket ustida qanday paketlar yurishini ko'rasiz.
  • emit/on, ack va emitWithAck (timeout bilan) ishlatasiz.
  • Rooms, namespaces, middleware auth va broadcast modifikatorlarini kanon tajribasida ko'rasiz.
  • Express bilan bitta portda ulaysiz.
  • Socket.IO, ws va SSE kechikishini bir xil sharoitda o'lchab solishtirasiz.

Oldin bilishingiz kerak: WebSocket protokoli va ws, Realtime usullari va tanlov, Middleware va request lifecycle, EventEmitter asoslari.

Oldingi darsda ws bilan auth, heartbeat va backpressure'ni qo'lda qildik. Socket.IO bularning ko'pini o'zi qiladi — bugun nima evaziga ekanini ko'ramiz.

1. Nega bu kerak?

ws bilan chat yozayotgan Aziz bir hafta ichida quyidagilarni o'zi yozdi: xabar turini ajratish ({"tur":"xabar",...}), "server oldimi?" javobi, qayta ulanish, bir foydalanuvchining hamma oynalariga yuborish, ping/pong. Bularning hammasi har realtime ilovada kerak. Socket.IO — shu takrorlanadigan ishning tayyor kutubxonasi.

O'xshatish: ws — oddiy telefon liniyasi. Socket.IO — ofis ATS'i: ichki raqamlar (xonalar), bo'limlar (namespace'lar), "qo'ng'iroqni qabul qildim" tasdig'i (ack), liniya uzilsa qayta terish.

2. Socket.IO ichida nima bor

2.1 Ikki qatlam

Socket.IO ikki qatlamdan iborat:

  1. Engine.IO — transport: WebSocket yoki HTTP long polling, ping/pong, qayta ulanish.
  2. Socket.IO — uning ustida: hodisa nomlari, ack, namespace, xona.

Shuning uchun Socket.IO serveri bilan faqat Socket.IO mijozi gaplasha oladi. Oddiy new WebSocket("ws://…") ulanadi, lekin protokolni bilmasa, hech narsa olmaydi.

2.2 Simdagi paketlar

Biz Socket.IO 4.8.4 serveriga Node'ning oddiy WebSocket mijozi bilan ulandik va paketlarni qo'lda yubordik (sid — tasodifiy sessiya ID, … bilan almashtirdik):

js
const ws = new WebSocket(
  `ws://127.0.0.1:${port}/socket.io/?EIO=4&transport=websocket`,
);
ws.onmessage = (e) => {
  console.log("server →", String(e.data));
  if (String(e.data).startsWith("0")) ws.send("40");
  if (String(e.data).startsWith("42")) ws.send('421["salom",7]');
};
// serverda: s.emit("xush", "kelibsiz");
//           s.on("salom", (x, ack) => ack({ olindi: x }));

Natija (biz ishga tushirdik, Node 24.21.0):

text
server → 0{"sid":"…","upgrades":[],"pingInterval":25000,"pingTimeout":20000,"maxPayload":1000000}
mijoz  → 40
server → 40{"sid":"…"}
server → 42["xush","kelibsiz"]
mijoz  → 421["salom",7]
server → 431[{"olindi":7}]

Har paketning birinchi raqami — tur:

Paket Ma'nosi
0{…} Engine.IO ochildi: ping oralig'i, maksimal hajm
40 Socket.IO: asosiy namespace'ga ulanish
42[...] hodisa: nomi va argumentlari, JSON
421[...] / 431[...] 1-raqamli ack so'rovi va unga javob

pingInterval: 25000 — server har 25 soniyada ping yuboradi, pingTimeout: 20000 — javobni shuncha kutadi. Oldingi darsda qo'lda yozgan heartbeat shu yerda tayyor. maxPayload: 1000000 — 1 MB limit (maxHttpBufferSize sozlamasi).

3. Server va mijoz

3.1 Express bilan bitta portda

bash
npm i socket.io@4.8.4 socket.io-client@4.8.4
ts
import http from "node:http";
import express from "express";
import { Server } from "socket.io";

const app = express();
app.get("/api/salomatlik", (_req, res) => {
  res.json({ ok: true });
});

const server = http.createServer(app); // Express — so'rov ishlovchisi
const io = new Server(server, {
  cors: { origin: ["https://vazifalar.example.uz"] },
});

io.on("connection", (socket) => {
  socket.on("vazifa:bajar", (id: number) => { /* ... */ });
});

server.listen(4000); // app.listen EMAS

Asosiy nuqta: app.listen() emas, http.createServer(app) va server.listen(). app.listen o'z serverini ichida yaratadi — Socket.IO unga ulana olmaydi. cors sozlamasi — HTTP long polling so'rovlari uchun (CORS chuqur).

Mijoz (brauzerda):

js
import { io } from "socket.io-client";

const socket = io("https://vazifalar.example.uz", {
  withCredentials: true,
});
socket.on("connect", () => console.log("ulandi", socket.id));
socket.on("vazifa:yangilandi", (v) => yangila(v));

3.2 emit va on

Hodisa nomi — erkin satr. Kelishuv: resurs:amal (vazifa:yangilandi, xabar:yangi). Argumentlar JSON qilinadi; Buffer/ArrayBuffer binar sifatida ketadi.

connect, disconnect, connect_error — zaxira nomlar, o'zingiz emit qilmang.

4. Ack: javobni kutish

4.1 Callback va emitWithAck

Oddiy emit — "yubordim, keyin nima bo'lsa ham". Ba'zan javob kerak: "vazifa saqlandimi, ID si nima?". Buning uchun oxirgi argument — funksiya. Server uni chaqirsa, javob mijozga qaytadi. Kanon serveri (formatlangan):

js
socket.on("vazifa:bajar", (id, ack) => {
  if (typeof ack !== "function") return; // mijoz ack so'ramagan
  id === 404
    ? ack({ ok: false, xato: "topilmadi" })
    : ack({ ok: true, id });
});
socket.on("sekin", (_x, ack) => setTimeout(() => ack("kech"), 500));

Mijoz — Promise bilan:

js
const r1 = await a.emitWithAck("vazifa:bajar", 5);
const r2 = await a.emitWithAck("vazifa:bajar", 404);
try {
  await a.timeout(100).emitWithAck("sekin", 1);
} catch (e) {
  console.log("ack timeout 100 ms:", e.message);
}

Kanon natijasi:

text
ack: {"ok":true,"id":5} {"ok":false,"xato":"topilmadi"}
ack timeout 100 ms: operation has timed out

Server 500 ms kutdi, mijoz esa 100 ms dan keyin taslim bo'ldi. Timeout'siz emitWithAck abadiy kutishi mumkin — server javob bermasa yoki ulanish uzilsa. Har ack'ga timeout() qo'ying.

typeof ack !== "function" tekshiruvi muhim: mijoz ack'siz emit qilsa yoki ataylab boshqa narsa yuborsa, ack(...) chaqiruvi TypeError bilan ishlovchini yiqitadi.

4.2 Ack — "server qabul qildi", xolos

Ack — server ishlovchisi ack() ni chaqirgani. Bu "boshqa foydalanuvchi oldi" degani emas. Chatda "yuborildi " va "yetkazildi " — ikki xil ack, Amaliyot: chat va bildirishnomalar darsida.

5. Rooms, namespaces va middleware

5.1 Tuzilma

flowchart TD
  IO[Server io] --> N1[Namespace /]
  IO --> N2[Namespace /admin]
  N1 --> R1[xona foydalanuvchi:1]
  N1 --> R2[xona foydalanuvchi:2]
  N1 --> R3[xona loyiha:7]
  R1 --> S1[telefon]
  R1 --> S2[noutbuk]
  R3 --> S1
  R3 --> S3[Dilnoza]
  N2 --> S4[admin paneli]

Diagrammaga qarang: namespace — alohida "kanal" (o'z middleware'i va hodisalari bilan), mijoz unga alohida ulanadi. Xona (room) — server tomonidagi guruh, mijoz uni bilmaydi. Bitta ulanish ko'p xonada bo'lishi mumkin: telefon ham foydalanuvchi:1 da, ham loyiha:7 da.

5.2 Middleware auth

js
io.use((socket, next) => {
  const t = socket.handshake.auth?.token;
  if (!t?.startsWith("u:")) return next(new Error("ruxsat yo'q"));
  socket.data.fId = Number(t.slice(2));
  next();
});

Bu Express middleware'iga o'xshaydi, lekin har ulanish uchun bir marta ishlaydi (har hodisa uchun emas). next(new Error(...)) — ulanish rad etiladi, mijozda connect_error hodisasi xabar bilan chiqadi. socket.data — ulanishga bog'langan ma'lumot. Kanondagi u:1 tokeni — tajriba soddaligi uchun; haqiqiysi — sessiya cookie'si (socket.request.headers.cookie) yoki imzolangan token (28-qismda JWT anatomiyasi).

5.3 Foydalanuvchi xonasi

Kanon har ulanishni foydalanuvchi:<id> xonasiga qo'shadi. Foydalanuvchi 1 ikki oynadan (a, a2), foydalanuvchi 2 bitta oynadan (b) ulandi:

js
io.on("connection", (s) => s.join(`foydalanuvchi:${s.data.fId}`));
io.to("foydalanuvchi:1").emit("vazifa:yangilandi", { id: 7 });
io.except("foydalanuvchi:2").emit("vazifa:yangilandi", { id: 8 });

Kanon natijasi:

text
token yo'q: ruxsat yo'q
room foydalanuvchi:1 ga emit → a2:7, a:7
text
except(foydalanuvchi:2): a2:8, a:8

to(...) — faqat xonadagilar; except(...) — hammaga, shu xonadan tashqari. b ikkala holatda ham olmadi. Bu SSE'dagi SseHub ning Map<fId, Set<Response>> tuzilmasi bilan bir xil g'oya — Socket.IO'da tayyor.

5.4 Namespace o'z middleware'i bilan

js
const admin = io.of("/admin");
admin.use((so, next) =>
  next(so.handshake.auth?.token === "u:1"
    ? undefined
    : new Error("admin emas")));
text
/admin namespace, foydalanuvchi 2: admin emas

Foydalanuvchi 2 asosiy namespace'ga kira oladi, /admin ga — yo'q. Namespace — rol bo'yicha ajratishning qulay joyi (RBAC va resurs egaligi, 28-qism).

5.5 Broadcast modifikatorlari

Ifoda Kimga
io.emit(...) hamma ulanishlarga
socket.broadcast.emit(...) yuboruvchidan boshqa hammaga
io.to("x").to("y").emit(...) x yoki y xonasidagilarga (birlashma)
io.except("x").emit(...) x dan boshqa hammaga
socket.to("x").emit(...) x dagilarga, yuboruvchisiz
io.volatile.emit(...) yetmasa — tashlanadi
io.timeout(ms).emit(..., cb) har qabul qiluvchidan ack kutadi

volatile — "yozmoqda…" kabi muhim bo'lmagan hodisalar uchun: mijoz tayyor bo'lmasa, navbatga qo'yilmaydi. Oldingi darsdagi "tashlash" siyosati.

Tekshirib ko'ring: Mijoz socket.emit("join", "loyiha:7") yuborsa, server so'zsiz socket.join(xona) qilsa nima bo'ladi?

Javob

Har kim istalgan xonaga kira oladi — masalan begona loyihaning hamma yangilanishlarini oladi. Xona nomi mijozdan kelsa, server avval huquqni tekshirishi shart: foydalanuvchi shu loyiha a'zosimi (bazada). Eng xavfsizi — xonalarni faqat server o'zi tanlaydi (foydalanuvchi:${socket.data.fId} kabi).

6. Transport, qayta ulanish va narx

6.1 Polling'dan WebSocket'ga

Sukut bo'yicha Socket.IO mijozi avval HTTP long polling bilan ulanadi, keyin WebSocket'ga "ko'tariladi" (upgrade). Sabab: ba'zi korporativ proksilar WebSocket'ni bloklaydi — polling baribir ishlaydi. Narxi: bir nechta qo'shimcha HTTP so'rov va ko'p serverda sticky session talabi (Realtime'ni masshtablash). Kanon tajribalari transports: ["websocket"] bilan — faqat WebSocket.

Uzilsa, mijoz o'zi qayta ulanadi (eksponensial kutish — exponential backoff, Taymerlar darsida ko'rgansiz). Lekin uzilish paytidagi hodisalar sukut bo'yicha yo'qoladi. Ularni qaytarish — "connection state recovery" — keyingi darsda.

6.2 Ulanish narxi

Kanon bitta jarayonda 2 000 Socket.IO (websocket) ulanish ochdi va hammasiga bitta xabar yubordi:

text
2000 ulanish 2120 ms; RSS +114.3 MB (server + 2000 mijoz, ~58.5 KB/ulanish ikkala tomon); broadcast 2000 ga: oxirgisi 100 ms, mediana 78 ms

~58.5 KB — server va mijoz birgalikda (ikkalasi bitta jarayonda edi). Serverning o'z ulushi kichikroq, lekin bu o'lchovda alohida ajratilmagan. Shu tartibdagi raqam bilan rejalashtiring: 10 000 ochiq ulanish — yuzlab megabayt.

7. O'lchov: Socket.IO, ws va SSE

Realtime usullari va tanlov darsidagi kanon tajribasida Socket.IO yo'q edi. Biz o'sha usul bilan (100 mijoz, 20 hodisa, har 200 ms, bitta jarayon, lokal) to'rt variantni o'lchadik va uch marta qaytardik. Mashina — kanondagi i5-12500H, Windows 11, Node 24.21.0; ws 8.22.0, undici 8.12.3, socket.io 4.8.4. Uchta ## f40 blokining har birida faqat mediana ustuniga qarang va to'rt qatorni solishtiring:

text
## f40 — 2026-10-28 — Node v24.21.0; ws 8.22.0, undici 8.12.3, socket.io 4.8.4
SSE (undici EventSource)       qabul 2000/2000, mediana 7.9 ms, p95 17.5 ms
WS (ws)                        qabul 2000/2000, mediana 5.3 ms, p95 33.7 ms
Socket.IO (faqat websocket)    qabul 2000/2000, mediana 8.1 ms, p95 18.0 ms
Socket.IO (sukut: polling→ws)  qabul 2000/2000, mediana 5.2 ms, p95 10.4 ms
## f40 — 2026-10-28 — Node v24.21.0; ws 8.22.0, undici 8.12.3, socket.io 4.8.4
SSE (undici EventSource)       qabul 2000/2000, mediana 12.5 ms, p95 35.4 ms
WS (ws)                        qabul 2000/2000, mediana 5.5 ms, p95 17.6 ms
Socket.IO (faqat websocket)    qabul 2000/2000, mediana 5.7 ms, p95 25.2 ms
Socket.IO (sukut: polling→ws)  qabul 2000/2000, mediana 5.4 ms, p95 26.1 ms
## f40 — 2026-10-28 — Node v24.21.0; ws 8.22.0, undici 8.12.3, socket.io 4.8.4
SSE (undici EventSource)       qabul 2000/2000, mediana 7.1 ms, p95 15.2 ms
WS (ws)                        qabul 2000/2000, mediana 8.7 ms, p95 33.7 ms
Socket.IO (faqat websocket)    qabul 2000/2000, mediana 8.6 ms, p95 26.1 ms
Socket.IO (sukut: polling→ws)  qabul 2000/2000, mediana 10.2 ms, p95 44.1 ms

Nima bo'ldi? Uchala o'lchovni yonma-yon qo'ying:

  • Hamma variant hamma 2 000 hodisani oldi.
  • Medianalar 5–13 ms oralig'ida. Birinchi o'lchovda eng tezi Socket.IO (polling→ws), uchinchisida — SSE. O'rinlar har safar almashdi.
  • p95 ham sakraydi (10–44 ms): bitta jarayonda 100 mijoz va server bir-biri bilan protsessor talashadi.

Xulosa: bu sharoitda kechikish farqi o'lchov shovqinidan kichik. Kanonning birinchi o'lchovidagi "WS 3.8 ms, SSE 16.2 ms" ham shu shovqinning bitta namunasi. Tanlov sababi — imkoniyatlar: SSE oddiy HTTP va bir tomonlama; ws — yengil, hammasi qo'lda; Socket.IO — xonalar, ack, qayta ulanish, fallback, lekin o'z protokoli va mijoz kutubxonasi (bundle hajmi) bilan.

Tajriba bitta mashinada; tarmoq, TLS, minglab mijoz va alohida jarayonlar bilan raqamlar boshqacha bo'ladi. Bu o'lchovdan "kim tezroq" degan qoida chiqarmang.

8. Hujumchi nigohi

Hujum Himoya
tokensiz ulanish io.use middleware, next(new Error)
begona xonaga join so'rovi xonani server tanlaydi yoki huquq tekshiruvi
ack o'rniga boshqa tur yuborish typeof ack === "function"
noto'g'ri tuzilmali hodisa ma'lumoti har ishlovchida Zod validatsiyasi
sekundiga minglab emit hodisa bo'yicha rate limit, ulanishni uzish
boshqa saytdan cookie bilan ulanish cors.origin oq ro'yxati, allowRequest da Origin

Socket.IO'da har socket.on("…") — alohida API marshruti. REST'dagi hamma qoidalar (OWASP API Security Top 10) bu yerda ham amal qiladi: kirish ma'lumotini tekshirish, egalik, limitlar. Faqat ular HTTP log va middleware zanjirida ko'rinmaydi — shuning uchun tez-tez unutiladi.

9. Ko'p uchraydigan xatolar

Xato Natijasi To'g'risi
app.listen() + new Server(app) Socket.IO ulanmaydi http.createServer(app)
oddiy WebSocket bilan ulanish paketlar tushunilmaydi socket.io-client
timeout'siz emitWithAck abadiy kutish socket.timeout(ms)
ack turini tekshirmaslik TypeError, ishlovchi yiqiladi typeof ack === "function"
mijozdan kelgan xona nomiga join begona ma'lumot sizadi huquq tekshiruvi
klient va server major versiyasi farqli ulanish xatosi bir xil 4.x
connect/disconnect nomini emit qilish zaxira nom xatosi o'z nomlaringiz

10. Mashqlar

Mashqlar kurs/mashqlar/29/40-socketio/ da.

1-mashq (oson): bo'shliqlarni to'ldiring

  • Yuboruvchidan boshqa hammaga: socket..emit(...)
  • Yetmasa tashlanadigan hodisa: io..emit(...)
  • Ack'ni Promise bilan kutish: await socket.("nom", x)
  • Har ulanish uchun auth: io.((socket, next) => ...)
  • Hodisa paketi raqami simda: ["nom", ...]
Yechim
  • broadcast — yuboruvchining o'zi olmaydi.
  • volatile — "yozmoqda…" kabi muhim bo'lmagan hodisalar uchun.
  • emitWithAck — timeout() bilan birga.
  • use — har ulanishda bir marta, har hodisada emas.
  • 42 — 4 Engine.IO "xabar", 2 Socket.IO "hodisa".

2-mashq (o'rta): xonalar reyestri

Socket.IO'siz, oddiy JS bilan Xonalar klassini yozing: qoshil(ulanish, xona), chiq(ulanish) (hamma xonalardan) va qabulQiluvchilar({ to, except }) — to xonalaridagi ulanishlar birlashmasi, except xonalaridagilarsiz, saralangan massiv. Sinang: a1, a2 — foydalanuvchi:1, b1 — foydalanuvchi:2, uchalasi loyiha:7 da. Ishora: Map + Set (Map, Set).

Yechim
js
class Xonalar {
  #xonalar = new Map(); // xona → Set(ulanish)

  qoshil(ulanish, xona) {
    if (!this.#xonalar.has(xona)) this.#xonalar.set(xona, new Set());
    this.#xonalar.get(xona).add(ulanish);
  }

  chiq(ulanish) {
    for (const a of this.#xonalar.values()) a.delete(ulanish);
  }

  qabulQiluvchilar({ to = [], except = [] }) {
    const chetda = new Set(except.flatMap((x) => [...this.#a(x)]));
    const natija = new Set();
    for (const x of to) {
      for (const u of this.#a(x)) if (!chetda.has(u)) natija.add(u);
    }
    return [...natija].sort();
  }

  #a(xona) {
    return this.#xonalar.get(xona) ?? new Set();
  }
}

const x = new Xonalar();
x.qoshil("a1", "foydalanuvchi:1");
x.qoshil("a2", "foydalanuvchi:1");
x.qoshil("b1", "foydalanuvchi:2");
for (const u of ["a1", "a2", "b1"]) x.qoshil(u, "loyiha:7");

console.log(x.qabulQiluvchilar({ to: ["foydalanuvchi:1"] }));
console.log(x.qabulQiluvchilar({
  to: ["loyiha:7"], except: ["foydalanuvchi:2"],
}));
x.chiq("a2");
console.log(x.qabulQiluvchilar({
  to: ["loyiha:7", "foydalanuvchi:2"],
}));

Konsolda:

text
[ 'a1', 'a2' ]
[ 'a1', 'a2' ]
[ 'a1', 'b1' ]

Uchinchi holatda b1 ikki xonada bo'lsa ham bir marta chiqdi — Set takrorni oladi. Socket.IO ham shunday: io.to("a").to("b") bir ulanishga bitta xabar yuboradi. Uning ichki "adapter"i aynan shu ishni qiladi — keyingi darsda bir nechta server uchun adapterni almashtiramiz.

3-mashq (qiyin): auth va validatsiyali ack

Haqiqiy Socket.IO bilan (o'z papkangizda npm i socket.io@4.8.4 socket.io-client@4.8.4) server yozing: middleware tokeni u: bilan boshlanmasa ruxsat yo'q bilan rad etsin; vazifa:qosh hodisasi matn bo'sh bo'lmagan satr bo'lsa { ok: true, egasi, matn } (matn 100 belgigacha qirqilgan), aks holda { ok: false, xato: "matn kerak" } ni ack bilan qaytarsin. Mijoz: x token bilan urinib ko'rsin, keyin u:7 bilan ikki marta emitWithAck qilsin. Faqat websocket transporti.

Yechim
js
import http from "node:http";
import { once } from "node:events";
import { Server } from "socket.io";
import { io } from "socket.io-client";

const h = http.createServer();
const srv = new Server(h, { transports: ["websocket"] });
srv.use((s, next) => {
  const t = s.handshake.auth?.token;
  if (!t?.startsWith("u:")) return next(new Error("ruxsat yo'q"));
  s.data.fId = Number(t.slice(2));
  next();
});
srv.on("connection", (s) => {
  s.on("vazifa:qosh", (v, ack) => {
    if (typeof ack !== "function") return;
    if (typeof v?.matn !== "string" || v.matn.length === 0) {
      ack({ ok: false, xato: "matn kerak" });
      return;
    }
    ack({ ok: true, egasi: s.data.fId, matn: v.matn.slice(0, 100) });
  });
});
h.listen(0, "127.0.0.1");
await once(h, "listening");
const url = `http://127.0.0.1:${h.address().port}`;
const opt = { transports: ["websocket"], forceNew: true };

const yomon = io(url, { ...opt, auth: { token: "x" } });
const [xato] = await once(yomon, "connect_error");
console.log("token x:", xato.message);
yomon.close();

const m = io(url, { ...opt, auth: { token: "u:7" } });
await once(m, "connect");
const v = { matn: "Non olish" };
console.log(await m.emitWithAck("vazifa:qosh", v));
console.log(await m.emitWithAck("vazifa:qosh", {}));
m.close();
srv.close();

Konsolda:

text
token x: ruxsat yo'q
{ ok: true, egasi: 7, matn: 'Non olish' }
{ ok: false, xato: 'matn kerak' }

egasi mijoz yuborgan ma'lumotdan emas, socket.data dan — middleware'da aniqlangan. Mijoz { matn, egasi: 1 } yuborsa ham, server uni e'tiborsiz qoldiradi (mass assignment'dan himoya, Backend'dagi injection va mass assignment). Productionda v ni Zod sxemasi bilan tekshiring. Yechimni biz ishga tushirdik (socket.io 4.8.4, Node 24.21.0).

11. Loyiha qadami: kanon tajribasi

Socket.IO vazifalar-api ga kirmaydi: kanon qarori bo'yicha vazifa o'zgarishlari — SSE (SseHub). Bu darsdagi asoslar (ack, xonalar, namespace, ulanish narxi) — kanon o'lchovi (IlmHamroh, 2026-10) (socket.io 4.8.4, 2026-10-27). Simdagi paketlar, kechikish o'lchovi va 3-mashq — biz ishga tushirdik (2026-10-28).

Nega bunday qaror? vazifalar da mijoz serverga REST bilan yozadi, server esa faqat xabar beradi. SSE buni qo'shimcha protokol va mijoz kutubxonasisiz qiladi. Socket.IO ikki tomonlama chat uchun kerak bo'ladi — Amaliyot: chat va bildirishnomalar darsida.

12. Real ishda

  • Socket.IO — Node realtime'ida eng ko'p uchraydigan kutubxona; Java, Python, Go, Swift, Kotlin uchun ham mijozlari bor.
  • NestJS gateway'lari sukut bo'yicha Socket.IO ustida ishlaydi — 30-qismda.
  • Ko'p jamoa yangi loyihada oddiy holatlar uchun SSE yoki ws ni, xonalar va ack kerak bo'lganda Socket.IO'ni tanlaydi.
  • Intervyuda: "Socket.IO va WebSocket farqi?", "Room va namespace farqi?", "Ack nima uchun kerak?", "Socket.IO'da auth qayerda?"

Xulosa

  • Socket.IO — Engine.IO (transport, ping) ustidagi protokol; oddiy WebSocket mijoz u bilan gaplasha olmaydi.
  • emit/on — nomli hodisalar; ack — server qabul qilganining tasdig'i; emitWithAck doim timeout() bilan.
  • Xona — server tomonidagi guruh (foydalanuvchi, loyiha); namespace — o'z middleware'i bilan alohida kanal.
  • Auth — io.use da, har ulanishda bir marta; xona nomini mijozga ishonmang.
  • Bizning uch o'lchovimizda SSE, ws va Socket.IO medianalari 5–13 ms va o'rni almashdi — tanlov imkoniyat bo'yicha.

Keyingi dars: Realtime'ni masshtablash — ikki server bo'lganda xabar nega yetmaydi, Redis adapter, connection state recovery va presence.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!