Stream orqali chat app quramiz.

Habibov Ulug'bek
4 min readNov 13, 2024

--

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. Agarda false,qilib berilsa o`qiydigan tomon o`chirilganda yozadigan tomon socket avtomatik tarzda yopiladi. Default: false.
  • highWaterMark :number . Bu ixtiyoriy agarda berilganda net.Socket dagi hammareadableHighWaterMark va writableHighWaterMark, larni o`zgartiradi . Default: stream.getDefaultHighWaterMark() ga teng .
  • keepAlive :boolean .Agarda true, 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 .

OSI modeli haqida maqola.

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:

  1. Buffer haqida bilib olamiz (Nodejs).
  2. Stream nima? Nodejsda streamlar bilan ishlash.
  3. Streamlar bilan benchmarking qilish.
  4. 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

--

--

Habibov Ulug'bek
Habibov Ulug'bek

Written by Habibov Ulug'bek

Software Engineer | Backend Nodejs Developer

No responses yet