Socket.IO bilan ishlash
Socket.IO nima?
Socket.IO bu kuchli JavaScript kutubxonasi bo‘lib, u real vaqt rejimida, ikki yo‘nalishli va veb-mijozlar va serverlar o‘rtasida voqealarga asoslangan aloqani ta’minlaydi. U har bir platforma, brauzer yoki qurilmada ishlashga mo‘ljallangan bo‘lib, ishonchlilik va tezlikka birdek e’tibor qaratadi.
Asosiy xususiyatlar
- Real vaqtda ikki tomonlama aloqa - Mijozlar va serverlar o‘rtasida tezkor ma’lumotlarni uzatish imkonini beradi
- Avtomatik qayta ulanish - O‘chirish va qayta ulanishni avtomatik tarzda boshqaradi
- Xonani qo‘llab-quvvatlash - Guruh muloqoti uchun osongina kanallar yarating
- Binar ma’lumotlarni qo‘llab-quvvatlash - Binar ma’lumotlarni yuborish va qabul qilish (ArrayBuffer, Blob, File va boshqalar)
- Multiplexing - Nom maydonlari bilan bir nechta soketlarni ishlating
- Qayta tiklash imkoniyatlari - Agar WebSockets mavjud bo‘lmasa, avtomatik ravishda HTTP uzoq so‘roviga qaytadi
Foydalanish holatlari
- Haqiqiy vaqtda chat ilovalari
- Jonli bildirishnomalar
- Hamkorlik vositalari
- Onlayn o‘yin
- Jonli tahlil
- Hujjat bilan hamkorlik
- Haqiqiy vaqtda boshqaruv paneli
- IoT ilovalari
Socket.IO ikki qismdan iborat:
- Brauzerda ishlaydigan mijoz kutubxonasi
- Node.js uchun server tomonidagi kutubxona
Socket.IO o‘rnatilmoqda
Server tomonida o‘rnatish
Socket.IO ni Node.js loyihangizga npm yoki ip yordamida o‘rnating:
# Using npm
npm install socket.io
# Or using Yarn
yarn add socket.io
Mijoz tomonini sozlash
Mijoz kutubxonasini kiritish uchun quyidagi usullardan birini tanlang:
Variant 1: CDN (Tez boshlash)
<script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
Variant 2: NPM (ishlab chiqarish uchun tavsiya etiladi)
# Install the client library
npm install socket.io-client
# Or using Yarn
yarn add socket.io-client
Variant 3: ES6 modullaridan foydalanish
import { io } from 'socket.io-client';
Versiyaning mosligi
| Socket.IO versiyasi | Node.js versiyasi | Brauzerni qo‘llab-quvvatlash |
|---|---|---|
| v4.x | v12.22.0+ | Chrome 49+, Firefox 53+, Safari 10+ |
| v3.x | v10.0.0+ | Chrome 49+, Firefox 53+, Safari 10+ |
| v2.x | v6.0.0+ | Chrome 5+, Firefox 6+, Safari 5.1+ |
Eslatma: Ishlab chiqarish uchun mijoz va serverda bir xil versiyadan foydalanish tavsiya etiladi.
Socket.IO bilan oddiy suhbat ilovasi
Keling, Node.js va Socket.IO yordamida real vaqt rejimida oddiy chat ilovasini yarataylik.
Ushbu misol hech qanday loginni talab qilmaydi va asosiy funksionallikni namoyish etadi.
Serverni yaratish (app.js)
Quyidagi tarkibga ega app.js nomli yangi fayl yarating:
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
// Serve static files
app.use(express.static(path.join(__dirname, 'public')));
// Simple route
app.get('/', (req, res) => {
; res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// Socket.IO connection handler
io.on('connection', (socket) => {
console.log('A user connected');
// Handle new messages
socket.on('chat message', (msg) => {
console.log('Message received:', msg);
// Broadcast the message to all connected clients
io.emit('chat message', msg);
});
// Handle disconnection
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Mijozni yaratish (public/index.html)
public katalog yarating va quyidagi tarkibga ega index.html fayl qo‘shing:
<!DOCTYPE html>
<html>
<head>
<title>Simple Chat</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
}
#messages {
list-style-type: none;
margin: 0;
padding: 0;
margin-bottom: 20px;
border: 1px solid #ddd;
padding: 10px;
height: 400px;
overflow-y: auto;
}
#messages li {
padding: 8px 16px;
border-bottom: 1px solid #eee;
}
#messages li:last-child {
border-bottom: none;
}
#form {
display: flex;
margin-top: 10px;
}
#input {
flex-grow: 1;
padding: 10px;
font-size: 16px;
}
button {
padding: 10px 20px;
background: #4CAF50;
color: white;
border: none;
cursor: pointer;
margin-left: 10px;
}
button:hover {
background: #45a049;
}
</style>
</head>
<body>
<h1>Simple Chat</h1>
<ul id="messages"></ul>
<form id="form" action="#">
<input id="input" autocomplete="off" placeholder="Type your message..." />
<button>Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById('form');
const input = document.getElementById('input');
const messages = document.getElementById('messages');
// Handle form submission
form.addEventListener('submit', (e) => {
e.preventDefault();
const message = input.value.trim();
if (message) {
// Emit the message to the server
socket.emit('chat message', message);
// Clear the input
input.value = '';
}
});
// Listen for incoming messages
socket.on('chat message', (msg) => {
const item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
// Scroll to the bottom
messages.scrollTop = messages.scrollHeight;
});
</script>
</body>
</html>
Ilovani ishga tushiring
- Start the server:
node app.js
- Brauzeringizni oching va
http://localhost:3000ga o‘ting - Haqiqiy vaqtda yangilanishlarni ko‘rish uchun bir nechta brauzer oynalarini oching
Bu qanday ishlaydi
- Server statik fayllarga xizmat ko‘rsatish va Socket.IO ulanishini boshqarish uchun Express-dan foydalanadi
- Mijoz ulanganda, u barcha ulangan mijozlarga uzatiladigan xabarlarni yuborishi mumkin
- Mijoz tomoni JavaScript real vaqt rejimida xabarlarni yuborish va qabul qilishni boshqaradi
Keyingi qadamlar
Ushbu asosiy versiya ishlagandan so‘ng, siz quyidagilarni qo‘shishingiz mumkin:
- Har bir xabar uchun foydalanuvchi nomlari
- Foydalanuvchi qo‘shilish/chiqish bildirishnomalari
- Turli xil suhbat xonalari
- Xabarning doimiyligi
- Foydalanuvchi autentifikatsiyasi
Eslatma: Bu namoyish qilish uchun asosiy misol. Ishlab chiqarish muhitida siz xatolarni to‘g‘ri boshqarish, kiritilgan ma’lumotlarni tekshirish va xavfsizlik choralarini qo‘shishni xohlaysiz.
Foydalanuvchi nomlarini qo‘shish
Xabarlarga foydalanuvchi nomlarini qo‘shish orqali suhbatimizni kengaytiraylik. Birinchidan, foydalanuvchi nomlarini boshqarish uchun serverni o‘zgartiring:
// In app.js, modify the connection handler
io.on('connection', (socket) => {
console.log('A user connected');
// Store username with socket
socket.username = 'Anonymous';
// Handle new messages with username
socket.on('chat message', (msg) => {
io.emit('chat message', {
username: socket.username,
message: msg,
timestamp: new Date().toISOString()
});
});
// Handle username change
socket.on('set username', (username) => {
const oldUsername = socket.username;
socket.username = username || 'Anonymous';
io.emit('user joined', {
oldUsername: oldUsername,
newUsername: socket.username
});
});
// Handle disconnection
socket.on('disconnect', () => {
console.log('A user disconnected');
io.emit('user left', { username: socket.username });
});
});
Endi foydalanuvchi nomlarini boshqarish uchun mijozni yangilang:
<!-- Add username input at the top of the chat -->
<div id="username-container">
<input type="text" id="username-input" placeholder="Enter your username" />
<button id="set-username">Set Username</button>
</div>
<script>
// Add username handling
const usernameInput = document.getElementById('username-input');
const setUsernameBtn = document.getElementById('set-username');
let currentUsername = 'Anonymous';
setUsernameBtn.addEventListener('click', () => {
const newUsername = usernameInput.value.trim();
if (newUsername) {
socket.emit('set username', newUsername);
currentUsername = newUsername;
usernameInput.value = '';
}
});
// Update message display to show usernames
socket.on('chat message', (data) => {
const item = document.createElement('li');
item.innerHTML = `<strong>${data.username}:</strong> ${data.message}`;
messages.appendChild(item);
messages.scrollTop = messages.scrollHeight;
});
// Handle user join notifications
socket.on('user joined', (data) => {
const item = document.createElement('li');
item.className = 'system-message';
if (data.oldUsername === 'Anonymous') {
item.textContent = `${data.newUsername} has joined the chat`;
} else {
item.textContent = `${data.oldUsername} is now known as ${data.newUsername}`;
}
messages.appendChild(item);
messages.scrollTop = messages.scrollHeight;
});
// Handle user leave notifications
socket.on('user left', (data) => {
const item = document.createElement('li');
item.className = 'system-message';
item.textContent = `${data.username} has left the chat`;
messages.appendChild(item);
messages.scrollTop = messages.scrollHeight;
});
</script>
<style>
.system-message {
color: #666;
font-style: italic;
font-size: 0.9em;
}
</style>
Chat xonalarini qo‘shish
Keling, turli chat xonalarini yaratish va ularga qo‘shilish imkoniyatini qo‘shaylik. Birinchidan, serverni yangilang:
// In app.js, add room handling
const rooms = new Set(['general', 'random']);
io.on('connection', (socket) => {
// ... existing code ...
// Join a room
socket.on('join room', (room) => {
// Leave all rooms except the default one
socket.rooms.forEach(r => {
if (r !== socket.id) {
socket.leave(r);
socket.emit('left room', r);
}
});
// Join the new room
socket.join(room);
socket.emit('joined room', room);
// Notify others in the room
socket.to(room).emit('room message', {
username: 'System',
message: `${socket.username} has joined the room`,
timestamp: new Date().toISOString()
});
});
// Handle room creation
socket.on('create room', (roomName) => {
if (!rooms.has(roomName)) {
rooms.add(roomName);
io.emit('room created', roomName);
}
});
// Modify message handler to send to room
socket.on('chat message', (data) => {
const room = Array.from(socket.rooms).find(r => r !== socket.id) || 'general';
io.to(room).emit('chat message', {
username: socket.username,
message: data.message,
timestamp: new Date().toISOString(),
room: room
});
});
});
Xonalarni boshqarish uchun mijozni yangilang:
<div id="chat-container">
<div id="sidebar">
<h3>Rooms</h3>
<ul id="room-list">
<li class="room active" data-room="general">General</li>
<li class="room" data-room="random">Random</li>
</ul>
<div id="create-room">
<input type="text" id="new-room" placeholder="New room name" />
<button id="create-room-btn">Create Room</button>
</div>
</div>
<div id="chat-area">
<div id="messages"></div>
<form id="form">
<input id="input" autocomplete="off" />
<button>Send</button>
</form>
</div>
</div>
<script>
// Room handling
const roomList = document.getElementById('room-list');
const newRoomInput = document.getElementById('new-room');
const createRoomBtn = document.getElementById('create-room-btn');
let currentRoom = 'general';
// Join room when clicking on room in the list
roomList.addEventListener('click', (e) => {
if (e.target.classList.contains('room')) {
const room = e.target.dataset.room;
socket.emit('join room', room);
currentRoom = room;
document.querySelectorAll('.room').forEach(r => r.classList.remove('active'));
e.target.classList.add('active');
}
});
// Create new room
createRoomBtn.addEventListener('click', () => {
const roomName = newRoomInput.value.trim();
if (roomName && !document.querySelector(`[data-room="${roomName}"]`)) {
socket.emit('create room', roomName);
newRoomInput.value = '';
}
});
// Handle new room creation
socket.on('room created', (roomName) => {
const roomItem = document.createElement('li');
roomItem.className = 'room';
roomItem.dataset.room = roomName;
roomItem.textContent = roomName;
roomList.appendChild(roomItem);
});
// Handle room join confirmation
socket.on('joined room', (room) => {
const item = document.createElement('li');
item.className = 'system-message';
item.textContent = `You joined ${room}`;
messages.appendChild(item);
currentRoom = room;
messages.scrollTop = messages.scrollHeight;
});
// Handle room messages
socket.on('room message', (data) => {
const item = document.createElement('li');
item.className = 'system-message';
item.textContent = data.message;
messages.appendChild(item);
messages.scrollTop = messages.scrollHeight;
});
</script>
<style>
#chat-container {
display: flex;
max-width: 1200px;
margin: 0 auto;
}
#sidebar {
width: 250px;
padding: 20px;
background-color: #f5f5f5;
border-right: 1px solid #ddd;
}
#chat-area {
flex: 1;
padding: 20px;
}
.room {
padding: 8px;
cursor: pointer;
border-radius: 4px;
margin: 4px 0;
}
.room:hover {
background-color: #e9e9e9;
}
.room.active {
background-color: #4CAF50;
color: white;
}
#create-room {
margin-top: 20px;
}
#new-room {
width: 100%;
padding: 8px;
margin-bottom: 8px;
}
#create-room-btn {
width: 100%;
padding: 8px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
#create-room-btn:hover {
background-color: #45a049;
}
</style>
Foydalanuvchilar ro‘yxatini qo‘shish va yozish ko‘rsatkichlari
Keling, foydalanuvchilar ro‘yxati va indikatorlarni yozish bilan suhbatimizni yaxshilaylik. Birinchidan, foydalanuvchilarni va yozish holatini kuzatish uchun serverni yangilang:
// In app.js, track users and typing status
const usersInRooms = new Map();
const typingUsers = new Map();
io.on('connection', (socket) => {
// ... existing code ...
// Initialize user data
socket.on('join room', (room) => {
// ... existing join room code ...
// Initialize user data for the room
if (!usersInRooms.has(room)) {
usersInRooms.set(room, new Map());
typingUsers.set(room, new Set());
}
// Add user to room
usersInRooms.get(room).set(socket.id, {
username: socket.username,
id: socket.id
});
// Send updated user list to room
updateUserList(room);
});
// Handle typing status
socket.on('typing', (isTyping) => {
const room = Array.from(socket.rooms).find(r => r !== socket.id);
if (!room) return;
if (isTyping) {
typingUsers.get(room).add(socket.username);
} else {
typingUsers.get(room).delete(socket.username);
}
// Notify room about typing users
io.to(room).emit('typing users', Array.from(typingUsers.get(room)));
});
// Handle disconnection
socket.on('disconnect', () => {
// Remove from all rooms
Array.from(usersInRooms.entries()).forEach(([room, users]) => {
if (users.has(socket.id)) {
users.delete(socket.id);
typingUsers.get(room)?.delete(socket.username);
updateUserList(room);
}
}
});
});
// Helper function to update user list for a room
function updateUserList(room) {
const users = Array.from(usersInRooms.get(room)?.values() || []);
io.to(room).emit('user list', {
room: room,
users: users.map(u => ({
username: u.username,
isTyping: typingUsers.get(room)?.has(u.username) || false
}))
});
}
});
});
Foydalanuvchilar ro‘yxatini ko‘rsatish va yozish ko‘rsatkichlarini boshqarish uchun mijozni yangilang:
<div id="chat-container">
<div id="sidebar">
<h3>Rooms</h3>
<ul id="room-list">
<!-- Room list will be populated here -->
</ul>
<div id="create-room">
<input type="text" id="new-room" placeholder="New room name" />
<button id="create-room-btn">Create Room</button>
</div>
<h3>Users in Room</h3>
<ul id="user-list">
<!-- User list will be populated here -->
</ul>
</div>
<div id="chat-area">
<div id="typing-indicator"></div>
<div id="messages"></div>
<form id="form">
<input id="input" autocomplete="off" placeholder="Type a message..." />
<button>Send</button>
</form>
</div>
</div>
<script>
// ... existing code ...
const userList = document.getElementById('user-list');
const typingIndicator = document.getElementById('typing-indicator');
const messageInput = document.getElementById('input');
let typingTimeout;
// Handle typing events
messageInput.addEventListener('input', () => {
// User is typing
if (!typingTimeout) {
socket.emit('typing', true);
}
// Clear previous timeout
clearTimeout(typingTimeout);
// Set a timeout to indicate user stopped typing
typingTimeout = setTimeout(() => {
socket.emit('typing', false);
typingTimeout = null;
}, 1000);
});
// Handle form submission
form.addEventListener('submit', (e) => {
e.preventDefault();
if (messageInput.value.trim()) {
socket.emit('chat message', {
message: messageInput.value,
room: currentRoom
});
messageInput.value = '';
// Clear typing status
if (typingTimeout) {
clearTimeout(typingTimeout);
typingTimeout = null;
socket.emit('typing', false);
}
}
});
// Update user list
socket.on('user list', (data) => {
if (data.room === currentRoom) {
userList.innerHTML = '';
data.users.forEach(user => {
const userItem = document.createElement('li');
userItem.textContent = user.username;
if (user.isTyping) {
userItem.innerHTML += ' <span class="typing">typing...</span>';
}
userList.appendChild(userItem);
});
}
});
// Update typing indicator
socket.on('typing users', (usernames) => {
const typingUsers = usernames.filter(u => u !== currentUsername);
if (typingUsers.length > 0) {
typingIndicator.textContent = `${typingUsers.join(', ')} ${typingUsers.length > 1 ? 'are' : 'is'} typing...`;
typingIndicator.style.display = 'block';
} else {
typingIndicator.style.display = 'none';
}
});
</script>
<style>
/* Add to existing styles */
#typing-indicator {
color: #666;
font-style: italic;
font-size: 0.9em;
padding: 5px 10px;
display: none;
}
.typing {
color: #666;
font-size: 0.8em;
font-style: italic;
}
#user-list {
list-style: none;
padding: 0;
margin: 10px 0;
}
#user-list li {
padding: 5px 10px;
border-radius: 3px;
margin: 2px 0;
}
#user-list li:hover {
background-color: #f0f0f0;
}
</style>
Client Side API umumiy ko‘rinishi
Mijoz tomonidagi Socket.IO API quyidagi usullarni taqdim etadi:
io()- Serverga ulanadisocket.emit()- hodisani serverga yuboradisocket.on()- Serverdagi voqealarni tinglaydisocket.disconnect()- serverdan uziladi
Socket.IO voqealari
Socket.IO aloqa uchun voqealarga asoslangan arxitekturadan foydalanadi. Mana bir nechta asosiy voqealar:
O‘rnatilgan tadbirlar
connect- Ulanish vaqtida ishga tushirildidisconnect- Aloqa uzilgandan keyin ishga tushirildierror- xato tufayli ishga tushirildireconnect- Muvaffaqiyatli qayta ulanishdan keyin ishga tushirildireconnect_attempt- qayta ulanishga urinishda ishga tushirildi
Socket.IO o‘rta dasturi
Socket.IO autentifikatsiya va boshqa maqsadlar uchun o‘rta dastur funksiyalarini aniqlash imkonini beradi:
const io = new Server(server);
// Middleware for authentication
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication error: Token missing'));
}
// Verify token (example with JWT)
try {
const user = jwt.verify(token, 'your-secret-key');
socket.user = user;
next();
} catch (error) {
next(new Error('Authentication error: Invalid token'));
}
});
io.on('connection', (socket) => {
console.log(`Authenticated user connected: ${socket.user.username}`);
});
Socket.IO va Native WebSockets
| Xususiyat | Socket.IO | Mahalliy WebSockets |
|---|---|---|
| Qayta tiklash mexanizmlari | Yes (HTTP long-polling, etc.) | Yo‘q |
| Avtomatik qayta ulanish | Ha | No (must implement) |
| Eshittirish | O‘rnatilgan | Qo‘lda amalga oshirish |
| Xonalar/Ismlar maydoni | O‘rnatilgan | Qo‘lda amalga oshirish |
| Brauzerni qo‘llab-quvvatlash | Barcha brauzerlar | Faqat zamonaviy brauzerlar |
| Paket hajmi | Larger (protocol overhead) | Kichikroq |
| Ikkilik ma’lumotlar | Qo‘llab-quvvatlanadi | Qo‘llab-quvvatlanadi |
Ishonchlilik, muvofiqlik va yuqori darajadagi funksiyalar kerak bo‘lganda Socket.IO afzal ko‘riladi, mahalliy WebSockets esa engilroq va kamroq yukga ega.
W3Schools Pathfinder
Yutuqlaringizni kuzating – bu bepul!
