Stream orqali chat app quramiz.
Assalamu Alaykum , bugun Nodejsning core moduli net bilan chat application quramiz.Ha ha to`g`ri sarlavhada stream deb yozilganku deyishingiz mumkin .Maqolani oxirigacha o`qing va buni bilib olasiz. Qani ketdik unda :).
Net moduli nima ?
Nodejsning o`zida net moduli bor bu ancha mashhur modul chunki backendda server qurmoqchi bo`lsangiz hammasi shunga kelib taqaladi .Bu modul bizga tcp based connection yaratishga yordam beradi .Unda faqat TCP emas IPC serverlarga ulanish yoki yaratish imkoniyatini ham beradi .Sizda savol kelib chiqishi mumkin TCP va UDPni eshitganman IPC nima ekan endi. IPC bu Inter-Process Communication (IPC) ya’ni computerda processlar o`rtasida aloqa o`rnatishga yordam beradi. Process bu biz ishlatayorgan dasturlar ya’ni siz video player bilan bog`lanib undagi ovozni textga o`tkazishingiz mumkin .Process haqida ko`proq bilib olish uchun ushbu maqolamni o`qib ko`ring.
Process va thread nima farqi bor ?
Note: Bu maqolada IPC haqida uncha to`xtalmaymiz bu haqida alohida maqola bo`ladi .
Xo`sh net modulini bilib oldik u bizga server yaratish yoki ulanish imkoniyatini berar ekan (TCP orqali) .Nodejsda http moduli ham bo`lib u ham http server qurishga yordam beradi, u ham under the hood net module ishlatadi.
Net modulida server yaratish va bog`lanish .
Server yaratish
net modulda net.createServer
funksiyasi orqali server yaratishingiz mumkin va u bir necha parametrlar qabul qiladi (Obyekt sifatida) .
allowHalfOpen
:boolean. Agardafalse
,qilib berilsa o`qiydigan tomon o`chirilganda yozadigan tomon socket avtomatik tarzda yopiladi. Default:false
.highWaterMark
:number . Bu ixtiyoriy agarda berilgandanet.Socket
dagi hammareadableHighWaterMark
vawritableHighWaterMark,
larni o`zgartiradi . Default:stream.getDefaultHighWaterMark()
ga teng .keepAlive
:boolean .Agardatrue
, berilsa bu keep-alive xususiyatini ishga soladi va connection saqlab qolinadi ,socket.setKeepAlive()
ga o`xshab ketadi . Default:false
.connectionListener
Function. Avtomatik tarzda'connection'
event uchun listener qo`shadi .
bular shulardan bir nechtasi.
va oxirida : net.Server qaytaradi . Server nimani eshitishiga listen()
qarab IPC yoki TCP server bo`ladi (port bu TCP bo`g`lanish uchun kerak agarda port bermasak serverga ma’lumotlar yetib keladigan eshik bo`lmaydi ) . Bu haqida ko`proq bilmoqchi bo`lsangiz ushbu maqolani tavsiya qilaman .
Qolgan net modul xususiyatlarini dokumentatsiyadan bilib olishingiz mumkin. Docs
Unda qani oddiy server kodini yozamiz.
import net from 'node:net';
const server = net.createServer((socket) => {
// 'connection' listener.
console.log('client connected');
socket.on('end', () => {
console.log('client disconnected');
});
socket.write('hello\r\n');
});
server.on('error', (err) => {
throw err;
});
server.listen(3000, () => {
console.log('server bound');
});
Client yaratish
Client yaratish uchun net modulning net.createConnection()
parametr sifatida bog`lanuvchi server porti va hostini berish orqali qilish mumkin undan keyin esa connection listener qo`shiladi. Bu serverdan kelgan eventlarni bilan ishlash uchun.
Qani kodini yozamiz:
import net from 'node:net';
const client = net.createConnection({ port: 8124 }, () => {
// 'connect' listener.
console.log('connected to server!');
client.write('world!\r\n');
});
client.on('data', (data) => {
console.log(data.toString());
client.end();
});
client.on('end', () => {
console.log('disconnected from server');
});
Xo`sh savol kelib chiqishi mumkin bu yerda net module ishlatdikku qani streamlar ?
Eng qiziq joyi endi boshlanadi har bir client serverga ulanganda client qismi uchun server bilan stream yaratiladi va u bilan ishlash uchun net.Socket obyekti beriladi bu duplex stream bo`lib yozish va o`qishga yordam beradi. Server qismi uchun har bir client bog`langanda socket yani connection listener beriladi u ham net.Socket obyekti bo`lib har bir client uchun har xil va duplex stream bo`ladi . Shu socket orqali client va server bir biriga ma’lumot uzatishi mumkin .Har bir serverga ulangan client uchun alohida stream ochiladi . Xo`sh qanday qilib unda bir foydalanuvchi yuborgan ma’lumot qolganlarga uzatiladi desangiz ? U serverga keladi va server ulanib turgan connectionlarni saqlab ularni har biriga qayta uzatadi .
Chat app quramiz !!
Server qism :
const net = require("net");
const crypto = require("crypto");
const server = net.createServer();
const clients = {};
server.on("connection", (socket) => {
const clientId = crypto.randomBytes(16).toString("hex");
Object.values(clients).map((s) => {
s.write(`New user connected: ${clientId}`);
});
socket.write(`Your ID is: ${clientId}`);
clients[clientId] = socket;
socket.on("data", (data) => {
const parsedData = JSON.parse(data);
Object.values(clients).map((s) => {
s.write(`${parsedData.clientId}: ${parsedData.message}\n`);
});
});
socket.on("end", () => {
handleClientLeave(clientId);
});
socket.on("error", () => {
handleClientLeave(clientId);
});
});
server.listen(3000, "127.0.0.1", () => {
console.log("Server address:", server.address());
});
const handleClientLeave = (clientId) => {
delete clients[clientId];
Object.values(clients).map((s) => {
s.write(`User disconnected: ${clientId}`);
});
};
bu yerda client Id uchun uuid ishlatilgan bu juda xunuk ko`rinadi ammo real projectda bu usernamega almashtiriladi.
Client code:
const net = require("net");
const readline = require("readline/promises");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const clearLine = (dir) => {
return new Promise((resolve, reject) => {
process.stdout.clearLine(dir, () => {
resolve();
});
});
};
const moveCursor = (dx, dy) => {
return new Promise((resolve, reject) => {
process.stdout.moveCursor(dx, dy, () => {
resolve();
});
});
};
let clientId = "";
const client = net.createConnection(3000, "127.0.0.1", async () => {
console.log("Connected to server");
const ask = async () => {
const message = await rl.question("Enter a message> ");
await moveCursor(0, -1);
await clearLine(0);
client.write(formatMessage(message));
};
ask();
client.on("data", async (data) => {
console.log(); // helps to be at next line
await moveCursor(0, -1);
await clearLine(0);
if (data.toString().includes("Your ID is:")) {
clientId = data.toString().split(":")[1].trim();
console.log(`Your ID is: ${clientId}`);
} else {
console.log(data.toString());
}
ask();
});
});
client.on("end", () => {
console.log("Disconnected from server");
});
const formatMessage = (message) => {
return JSON.stringify({
clientId,
message: message.trim(),
});
};
Bu yerda readline package chat terminalda chiroyli ko`rinishi va keraksiz yozuvlarni olib tashlash uchun ishlatilgan .
Ushbu kodlarni quyidagi repozitorida topishingiz mumkin. Github repo.
Xulosa
Ko`rib turganingizdek biz Nodejsning biroz qismini bilib uni mukammal o`rganganmiz deb o`ylaymiz.Birgina Net moduli orqali shuncha narsa qilishimiz mumkin.O`zim ham hayratdaman.
Yana Nodejsning shu kabi sirlarini bilmoqchi bo`lsangiz obuna bo`lib qo`ying hali hammasi oldinda .
Bundan oldingi Nodejsga aloqador maqolalar:
- Buffer haqida bilib olamiz (Nodejs).
- Stream nima? Nodejsda streamlar bilan ishlash.
- Streamlar bilan benchmarking qilish.
- Custom streamlar yozamiz(Nodejs).
Agarda maqola yoqqan bo`lsa chapak chaling (ko`p chalsayam bo`ladi 50 tagacha).
Xato va kamchiliklar uchun uzr !!!
linkedin.com => Ulug’bek Habibov | LinkedIn
telegram channel => @habibov_ulugbek