Socket.io — o'rnatish, room, namespace, broadcast
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.forEachhammaga 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.emitvasocket.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 yuborishsocket.broadcast.emit— o'zidan boshqa hammaga;io.emit— hammagasocket.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