Socket.io — o'rnatish, room, namespace, broadcast

~25 daq · Express · Real-time

Muammodan boshlaylik

Oldingi darsda ws moduli bilan WebSocket qurib ko'rdik. Lekin real loyihada muammolar boshlanadi:

  • Foydalanuvchi internetdan uzildi. Qayta ulanganda — hech nima yo'q. Xabarlarni o'zi qayta jo'natishi kerak.
  • 1000 ta foydalanuvchi bor. Shaxsiy xabar yubormoqchi bo'lasiz — qaysi socket kerakligini qanday topasiz?
  • Guruhli chat: bir xonada 50 kishi, boshqasida 30 kishi. wss.clients.forEach hammaga yuboradi.
  • Eski brauzerlar WebSocket ni qo'llamasa — butun loyiha ishlamay qoladi.

Har birini ws bilan o'zingiz yechishingiz mumkin — lekin bu haftalik ish. Socket.io bularning barchasini allaqachon hal qilgan.


Socket.io nima?

Socket.io — real-time aloqa uchun kutubxona. Ichida WebSocket ishlatadi, lekin ustiga juda ko'p qulayliklar qo'shgan.

Eng muhim farqlar ws dan:

ws (raw WebSocket) Socket.io
Faqat WebSocket WebSocket + fallback (long-polling)
Xona yo'q Room (guruh) mexanizmi bor
Reconnect yo'q Avtomatik qayta ulanish
Namespace yo'q Namespace (yo'l ajratish) bor
Middleware yo'q Middleware qo'llab-quvvatlaydi

💡 Socket.io WebSocket emas — WebSocket uning qurilishi. Socket.io o'z protokolini ishlatadi. Shuning uchun oddiy WebSocket klient Socket.io serverga ulana olmaydi.


Hayotiy o'xshatma

Tasavvur qiling: katta mehmonxona.

  • Namespace — mehmonxonaning turli bo'limlari: restoran, konferens-zal, fitnes-markaz. Har biri alohida kirish.
  • Room — bir bo'limdagi alohida xonalar: 101, 102, 103-xona. Bir konferens-zaldagi turli yig'ilishlar.
  • Broadcast — mehmonxona direktori: "Barcha mehmonlarga e'lon berilsin!" — hamma eshitadi.
  • Emit — ma'lum xona bo'yicha xabar: "Faqat 101-xona mehmonlariga qo'ng'iroq qiling."

Ws bilan esa hamma uchun bitta katta zal bor — hammani boshqarish o'zingizga qoladi.


O'rnatish

npm install socket.io

Mijoz (frontend) uchun:

npm install socket.io-client

Yoki CDN orqali HTML da:

<script src="/socket.io/socket.io.js"></script>

💡 /socket.io/socket.io.js — bu fayl Socket.io server tomonidan avtomatik taqdim etiladi. Alohida yuklab olishning hojati yo'q.


Server qanday ishlaydi?

Foydalanuvchi            Socket.io Server
    |                          |
    |--- HTTP: GET /           |
    |<-- 200 OK (sahifa) ------|
    |                          |
    |--- WebSocket handshake --|
    |<-- 101 Switching --------|
    |                          |
    |====== doimiy kanal =======|
    |                          |
    |--- emit('xabar') ------->|
    |<-- emit('javob') --------|
    |                          |
    X uzilib qoldi             |
    |                          |
    |--- qayta ulanish ------->|  ← Socket.io avtomatik
    |<-- muvaffaqiyatli -------|

Asosiy kod

Server

import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';

const app = express();
const httpServer = createServer(app); // ← Express va Socket.io bitta server

const io = new Server(httpServer, {
  cors: {
    origin: 'http://localhost:3000', // ← frontend manzili
    methods: ['GET', 'POST'],
  },
});

io.on('connection', (socket) => {
  console.log('Ulandi:', socket.id); // ← har foydalanuvchining noyob ID si

  socket.on('disconnect', () => {
    console.log('Uzildi:', socket.id);
  });
});

httpServer.listen(4000);

⚠️ new Server(app) emas — new Server(httpServer). Express ilovasi http serverga o'raladi, Socket.io shu serverga ulanadi.

Mijoz (React / oddiy JS)

import { io } from 'socket.io-client';

const socket = io('http://localhost:4000');

socket.on('connect', () => {
  console.log('Ulandi:', socket.id);
});

socket.on('disconnect', () => {
  console.log('Uzildi');
});

Emit — xabar yuborish

Socket.io da xabar yuborish emit() bilan. Istalgan nom, istalgan ma'lumot:

// Server → Mijoz
socket.emit('xabar', { matn: 'Salom!' });

// Mijoz → Server
socket.emit('yangi-xabar', { matn: 'Qanday?' });

// Server qabul qiladi
socket.on('yangi-xabar', (data) => {
  console.log(data.matn); // "Qanday?"
});

💡 socket.emit va socket.on — ikkalasi ham server va mijozda ishlaydi. Simmetrik protokol.


Broadcast — barchaga yuborish

io.on('connection', (socket) => {

  socket.on('xabar', (data) => {
    
    // Faqat o'ziga
    socket.emit('xabar', data);

    // O'zidan boshqa hammaga
    socket.broadcast.emit('xabar', data);

    // Hammaga (o'zi ham)
    io.emit('xabar', data);
  });
});

Chat uchun to'g'ri yondashuv:

socket.on('yangi-xabar', (data) => {
  // Yuborgandan boshqa hammaga — chunki o'zi allaqachon ko'rgan
  socket.broadcast.emit('yangi-xabar', {
    muallif: data.muallif,
    matn: data.matn,
    vaqt: new Date().toISOString(), // ← server vaqti — mijoz soatiga ishonmang
  });
});

Room — xonalar

Room — bir guruh socketlarni birlashtirish. Chat xonasi, o'yin sessiyasi, loyiha kanali — bularning barchasiga mos.

io.on('connection', (socket) => {

  // Xonaga kirish
  socket.on('xonaga-kir', (xonaId) => {
    socket.join(xonaId); // ← socket shu xonaga qo'shiladi
    
    // Faqat shu xonadagilarga
    io.to(xonaId).emit('xona-yangilandi', {
      xabar: `${socket.id} qo'shildi`,
    });
  });

  // Xonadan chiqish
  socket.on('xonadan-chiq', (xonaId) => {
    socket.leave(xonaId);
    io.to(xonaId).emit('xona-yangilandi', {
      xabar: `${socket.id} chiqdi`,
    });
  });

  // Faqat shu xonaga xabar
  socket.on('xona-xabar', ({ xonaId, matn }) => {
    io.to(xonaId).emit('yangi-xabar', {
      muallif: socket.id,
      matn,
    });
  });
});

Mijoz tomonida:

// Xonaga kirish
socket.emit('xonaga-kir', 'loyiha-123');

// Xonaga xabar yuborish
socket.emit('xona-xabar', {
  xonaId: 'loyiha-123',
  matn: 'Hammaga salom!',
});

// Xona xabarlarini qabul qilish
socket.on('yangi-xabar', (data) => {
  console.log(`${data.muallif}: ${data.matn}`);
});

💡 Har bir socket bir vaqtda bir nechta xonada bo'lishi mumkin. O'yinda ham bo'lishi mumkin — va bir vaqtda kompaniyaning umumiy kanalida ham.



To'liq chat misoli

// server.js
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
  cors: { origin: '*' },
});

io.on('connection', (socket) => {

  socket.on('kirish', ({ xonaId, ism }) => {
    socket.join(xonaId);
    socket.data.ism = ism;       // ← socketga ism saqlash
    socket.data.xonaId = xonaId; // ← socketga xona saqlash

    // Xonadagilarga bildirish (o'zidan boshqa)
    socket.to(xonaId).emit('foydalanuvchi-kirdi', { ism });
  });

  socket.on('xabar', (matn) => {
    const { ism, xonaId } = socket.data;

    // Faqat shu xonadagilarga
    io.to(xonaId).emit('yangi-xabar', {
      ism,
      matn,
      vaqt: new Date().toISOString(),
    });
  });

  socket.on('disconnect', () => {
    const { ism, xonaId } = socket.data;
    socket.to(xonaId).emit('foydalanuvchi-chiqdi', { ism });
  });
});

httpServer.listen(4000, () => console.log('Server 4000 portda'));

Tez-tez uchraydigan xatolar

1. new Server(app) o'rniga new Server(httpServer) ishlatmaslik

Sababi: Express ilovasi `http.Server` emas. Socket.io http serverga birikadi.
// ❌
const io = new Server(app);

// ✅
const httpServer = createServer(app);
const io = new Server(httpServer);

2. CORS xatosi

Access to XMLHttpRequest blocked by CORS policy
// ✅ — cors ni to'g'ri sozlang
const io = new Server(httpServer, {
  cors: {
    origin: 'http://localhost:3000',
    credentials: true, // ← cookie yuborsangiz
  },
});

3. Xonaga kirmay io.to() ishlatish

// ❌ — socket xonada emas, hech kim olmaydi
socket.on('xabar', (data) => {
  io.to('loyiha-123').emit('xabar', data); // ← avval join qiling!
});

// ✅
socket.on('kirish', (xonaId) => {
  socket.join(xonaId); // ← avval
});
socket.on('xabar', (data) => {
  io.to(data.xonaId).emit('xabar', data); // ← keyin
});

4. socket.emit va io.emit aralashtirib yuborish

// socket.emit  → faqat shu socket ga
// socket.to(id).emit → faqat shu socketga (boshqa socket)
// socket.broadcast.emit → o'zidan boshqa hammaga
// io.emit → hammaga (o'zi ham)
// io.to(xona).emit → faqat shu xonadagilarga

Xulosa

  • Socket.io — WebSocket ustiga qurilgan kutubxona: reconnect, room, fallback bepul
  • socket.join(xonaId) — xonaga kirish; io.to(xonaId).emit() — faqat shu xonaga yuborish
  • socket.broadcast.emit — o'zidan boshqa hammaga; io.emit — hammaga
  • socket.data — socket ga ma'lumot saqlash (ism, xonaId va h.k.)
  • Server vaqtini ishlating — mijoz soatiga ishonmang

Keyingi dars: 44-dars: Socket.io — autentifikatsiya, middleware