Mundarija (25)
- Bu darsda
- 1. Nega bu kerak?
- 2. net: TCP server va soket
- 2.1 Birinchi server
- 2.2 TCP'da xabar chegarasi yo'q
- 2.3 Soket hodisalari va yopilish
- 3. dns: nomdan IP'gacha
- 3.1 Ikki xil yo'l
- 3.2 Farq ko'rinadigan joy
- 3.3 Nega bu thread pool bilan bog'liq
- 4. IPv4, IPv6 va autoSelectFamily
- 5. tls: shifrlangan soket
- 5.1 Ulanish va sertifikat zanjiri
- 5.2 servername va xato
- 6. Hujumchi nigohi: rejectUnauthorized: false
- 7. CLI qadami: holat yo'q — fetch hammasini qiladi
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): qaysi qatlam?
- 2-mashq (o'rta): uzunlik prefiksli xabarlar
- 3-mashq (qiyin): kurs serveri — jami summa
- 4-mashq: CLI qadami — xatolarni qatlam bo'yicha ajrating
- 10. Real ishda
- Xulosa
- Manbalar
Node.js net, dns va tls: TCP soket, DNS so'rovi va TLS sertifikati
Qisqacha: HTTP — TCP ustidagi kelishuv.
node:netTCP darajasida ishlaydi.net.createServerulanishlarni qabul qiladi. Har ulanish — ikki tomonlama soket.node:dnsda ikki yo'l bor:dns.lookupoperatsion tizimdan so'raydi (hostsfayli, kesh),dns.resolve*esa to'g'ridan DNS serverga boradi.node:tlssoketni shifrlaydi va sertifikat zanjirini tekshiradi. Biz o'lchadik:localhostavval::1(IPv6) ga aylanadi — server faqat127.0.0.1da bo'lsa,autoSelectFamilyo'chiq ulanishECONNREFUSEDoladi.
Bu darsda
net.createServervanet.connectbilan kichik TCP server va mijoz yozasiz.- TCP'da xabar chegarasi yo'qligini va uni qator bilan qanday hal qilishni bilasiz.
dns.lookupvadns.resolvefarqini va qaysi biri qachon ishlatilishini tushuntirasiz.- IPv4/IPv6 va
autoSelectFamily(Happy Eyeballs) nima uchun kerakligini ko'rasiz. tls.connectbilan sertifikat zanjirini o'qiysiz vaservernamexatosini tushuntirasiz.
Oldin bilishingiz kerak: Protokol qatlamlari: TCP va UDP, Domen va DNS, HTTPS va TLS, libuv thread pool, readline va terminal.
1. Nega bu kerak?
valyuta CBU'ga fetch bilan murojaat qiladi va hammasi bitta qator: await fetch(url). Lekin shu qator ichida to'rt bosqich yashiringan:
cbu.uznomini IP manzilga aylantirish — DNS.- O'sha IP'ning 443-portiga ulanish — TCP.
- Ulanishni shifrlash va server haqiqatan
cbu.uzekanini tekshirish — TLS. - Shundan keyingina HTTP so'rov va javob.
Har bosqich o'z xatosi bilan yiqiladi: ENOTFOUND (nom topilmadi), ECONNREFUSED (port yopiq), ETIMEDOUT (javob yo'q), ERR_TLS_CERT_ALTNAME_INVALID (sertifikat boshqa domenga). Bu nomlarni ko'rib, muammo qaysi qatlamda ekanini bilsangiz — tuzatish ikki baravar tezlashadi. "Proxy ishlamayapti", "localhost'ga ulanmayapti", "sertifikat xatosi" — backend dasturchining kundalik muammolari.
O'xshatish: pochta orqali xat yuborish. DNS — manzillar kitobi (ism → uy manzili). TCP — pochtachi: xatlarni tartib bilan, yo'qotmasdan yetkazadi. TLS — muhrlangan konvert va pasport tekshiruvi: o'qib bo'lmaydi, oluvchi haqiqatan o'sha odam.
flowchart LR
A["fetch(cbu.uz)"] --> D["DNS<br/>nom → IP"]
D --> T["TCP<br/>185.203.237.70:443"]
T --> S["TLS<br/>shifr, sertifikat"]
S --> H["HTTP<br/>GET /json/"]Diagrammada har quti — Node'dagi alohida modul: dns, net, tls, keyin http. HTTP serverni 25-qismda o'zimiz yozamiz; bu dars — undan pastdagi qavatlar.
2. net: TCP server va soket
2.1 Birinchi server
Soket (socket) — ikki dastur orasidagi bitta TCP ulanishning bir uchi. U ham o'qiladigan, ham yoziladigan oqim: undan ma'lumot kelib turadi va unga yozasiz. Stream nima darsida bunday oqimni Duplex deb ataymiz.
Valyuta kursini beradigan kichik server: mijoz qator yuboradi (usd), server javob qaytaradi (USD 11903.15):
import net from "node:net";
import { createInterface } from "node:readline";
const RATES = { USD: 11903.15, EUR: 13372.4 };
const server = net.createServer((socket) => {
const rl = createInterface({ input: socket });
rl.on("line", (line) => {
const code = line.trim().toUpperCase();
const known = code in RATES;
const answer = known ? `${code} ${RATES[code]}` : `XATO ${code}`;
socket.write(answer + "\n");
});
});
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const { port } = server.address();
const client = net.connect(port, "127.0.0.1");
client.write("usd\neur\n");
client.end("gbp\n");
let reply = "";
for await (const chunk of client) reply += chunk;
console.log(reply.trim());
server.close();Konsolda:
USD 11903.15
EUR 13372.4
XATO GBPQadam-baqadam:
net.createServer(callback)— har yangi ulanishda callback chaqiriladi va unga soket beriladi.listen(0, "127.0.0.1")— 0-port "OS bo'sh portni o'zi tanlasin" degani. Tanlangan portserver.address().portda. Testlarda shunday qilinadi — port band bo'lib qolmaydi.valyutaning soxta CBU serveri ham shunday."127.0.0.1"— faqat shu kompyuterdan ulanish mumkin."0.0.0.0"(yoki host berilmasa) — tarmoqdagi boshqa kompyuterlardan ham.net.connect(port, host)— mijoz soketi.write— yuborish,end(...)— oxirgi xabar va "men boshqa yozmayman".for await (const chunk of client)— server javobini server ulanishni yopguncha o'qiydi.
2.2 TCP'da xabar chegarasi yo'q
Nega serverda readline ishlatdik? Chunki TCP — bayt oqimi, xabarlar ketma-ketligi emas. Mijoz uch marta write qildi, lekin server ularni bitta bo'lakda olishi mumkin — yoki bitta write ni ikki bo'lakda. TCP faqat baytlar tartibini va yo'qolmasligini kafolatlaydi.
Shuning uchun har protokol o'z chegaralash (framing) qoidasini kiritadi:
| Usul | Misol |
|---|---|
Qator oxiri (\n) |
Redis, SMTP, bizning kurs serveri |
| Uzunlik prefiksi (avval "keyingi xabar N bayt") | ko'p binar protokollar |
Sarlavha + Content-Length |
HTTP/1.1 |
Bizning serverda readline bo'laklarni yig'ib, faqat to'liq qatorlarni beradi — readline darsidagi "lag'mon" misolining tarmoqdagi ko'rinishi.
2.3 Soket hodisalari va yopilish
| Hodisa | Qachon |
|---|---|
"connect" |
mijoz ulandi |
"data" |
bo'lak keldi |
"end" |
qarshi tomon "boshqa yozmayman" dedi |
"close" |
soket butunlay yopildi |
"error" |
xato: ECONNREFUSED, ECONNRESET, ETIMEDOUT … |
socket.end() — muloyim yopish: "yozish tugadi". socket.destroy() — keskin uzish. socket.setTimeout(ms) — shuncha vaqt jim tursa "timeout" hodisasi (soketni o'zi yopmaydi — yopishni siz qilasiz).
Diqqat: Soketda
"error"tinglovchisi bo'lmasa, xato butun jarayonni yiqitadi. Biz sinovda mijozni keskin uzganimizda (destroy), server tomondagi soketread ECONNRESET("ulanish qarshi tomondan uzildi") oldi va serverUnhandled 'error' eventbilan tushdi. Bitta mijozning uzilishi butun serverni o'ldirmasligi uchun har soketgasocket.on("error", …)qo'ying. Nega"error"hodisasi bunchalik maxsus — EventEmitter asoslari darsida.
Tekshirib ko'ring: Mijoz
write("100 u")vawrite("sd\n")qildi. Bizning server nechta javob qaytaradi?
Javob
Bitta: XATO 100 USD. readline "100 u" ni qator oxiri kelguncha ushlab turadi, "sd\n" kelgach — bitta to'liq qator "100 usd". Bizning server faqat valyuta kodini kutadi, shuning uchun "100 USD" ni noma'lum kod deb javob beradi. Muhimi — ikki write bitta xabarga aylandi.
3. dns: nomdan IP'gacha
3.1 Ikki xil yo'l
node:dns da nomni IP'ga aylantirishning ikki butunlay boshqa yo'li bor:
dns.lookup |
dns.resolve4 / resolve6 / resolveMx … |
|
|---|---|---|
| Kim javob beradi | operatsion tizim (getaddrinfo) |
to'g'ridan DNS server (tarmoq orqali) |
hosts fayli |
o'qiydi | o'qimaydi |
| OS keshi | ishlatadi | yo'q |
| Qayerda bajariladi | libuv thread pool | asosiy thread'da, tarmoq orqali |
| Kim ishlatadi | net.connect, http, fetch |
siz, aniq DNS yozuvi kerak bo'lganda |
Kanon cbu.uz uchun ikkalasini o'lchadi (natijalar/tajriba/t26-net.txt): lookup — 1 ms (OS keshidan), resolve4 — 6 ms (DNS serverga borib keldi), natija bir xil: 185.203.237.70. Biz shu mashinada keyinroq qayta ishga tushirganimizda (Node 24.21.0, Windows 11) lookup 33 ms bo'ldi — OS keshi bo'shagan edi. Vaqt keshga bog'liq.
3.2 Farq ko'rinadigan joy
Biz bir nechta so'rovni ishga tushirdik (Node 24.21.0, Windows 11; tarmoqqa bog'liq):
import dns from "node:dns/promises";
console.log(await dns.lookup("localhost", { all: true }));
try {
await dns.resolve4("localhost");
} catch (e) {
console.log("resolve4 localhost:", e.code);
}
console.log(await dns.resolveMx("cbu.uz"));
try {
await dns.lookup("bunday-domen-yoq.example");
} catch (e) {
console.log(e.code, e.message);
}Biz ishga tushirgan chiqish:
[ { address: '::1', family: 6 }, { address: '127.0.0.1', family: 4 } ]
resolve4 localhost: ESERVFAIL
[
{ exchange: 'smtp.cbu.uz', priority: 20, type: 'MX' },
{ exchange: 'mail.cbu.uz', priority: 10, type: 'MX' }
]
ENOTFOUND getaddrinfo ENOTFOUND bunday-domen-yoq.exampleUchta saboq:
localhostnilookuptopdi (OS biladi),resolve4esa topa olmadi —ESERVFAIL.localhost— internet DNS'ida emas, kompyuterninghostsfaylida.resolveMx— pochta serverlari (MX yozuvlari). Bunday maxsus yozuvlarni faqatresolve*beradi. Email domenini tekshirish shunday qilinadi.ENOTFOUNDxabaridagetaddrinfoso'zi — bulookup(OS funksiyasi) ekanining belgisi.
3.3 Nega bu thread pool bilan bog'liq
libuv thread pool darsidan eslang: pool'da sukut bo'yicha 4 ta thread bor va fs ham, crypto ham, dns.lookup ham shu to'rttasini bo'lishadi. Sekin DNS server bo'lsa, lookup lar pool'ni egallaydi va fayl o'qish ham navbatda turadi. Ko'p tashqi so'rov yuboradigan serverlarda bu haqiqiy muammo. Yechimlar: UV_THREADPOOL_SIZE ni oshirish yoki DNS natijasini keshlash.
Tekshirib ko'ring:
hostsfayliga127.0.0.1 kurs.testqo'shildi.dns.lookup("kurs.test")vadns.resolve4("kurs.test")nima qaytaradi?
Javob
lookup — 127.0.0.1 (OS hosts faylini o'qiydi). resolve4 — xato (ENOTFOUND yoki ESERVFAIL): u DNS serverdan so'raydi, internetda kurs.test yo'q. fetch va net.connect lookup ni ishlatadi — shuning uchun hosts dagi nom ular uchun ishlaydi.
4. IPv4, IPv6 va autoSelectFamily
localhost ikki manzilga aylandi: avval ::1 (IPv6), keyin 127.0.0.1 (IPv4). Node 17 dan beri lookup natijalarni OS bergan tartibda qaytaradi (dns.getDefaultResultOrder() → "verbatim"). Endi server faqat IPv4 da tinglasa nima bo'ladi?
import net from "node:net";
const server = net.createServer((s) => s.end("salom\n"));
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const { port } = server.address();
for (const autoSelectFamily of [false, true]) {
await new Promise((done) => {
const opts = { port, host: "localhost", autoSelectFamily };
const c = net.connect(opts);
c.on("connect", () =>
console.log(autoSelectFamily, "→", c.remoteAddress));
c.on("error", (e) => {
console.log(autoSelectFamily, "→", e.code, e.address);
done();
});
c.on("close", done);
});
}
server.close();Biz ishga tushirgan chiqish (Windows 11):
false → ECONNREFUSED ::1
true → 127.0.0.1autoSelectFamily: false bo'lsa, Node faqat birinchi manzilni (::1) sinaydi. U yerda hech kim tinglamaydi — rad. true — Node Happy Eyeballs algoritmini ishlatadi: manzillarni navbat bilan, har biriga qisqa vaqt (sukut 250 ms) berib sinaydi va birinchi ulanganini oladi. Node 20 dan beri true — sukut (net.getDefaultAutoSelectFamily() → true).
Bu muammo 2022–2023 yillarda juda mashhur edi: Node 17 tartibni o'zgartirgach, "localhost:3000 ga ulanmayapti, 127.0.0.1:3000 ga ulanadi" degan savollar ko'paydi. Hozir sukut bo'yicha hal qilingan, lekin eski konfiguratsiyalarda yoki autoSelectFamily o'chirilgan kutubxonalarda hali ham uchraydi. Linux'da localhost tartibi /etc/hosts ga bog'liq (biz o'lchamadik).
5. tls: shifrlangan soket
5.1 Ulanish va sertifikat zanjiri
HTTPS va TLS darsida nazariyani ko'rgansiz: server sertifikat ko'rsatadi, sertifikatni ishonchli sertifikat markazi (CA) imzolagan, mijoz zanjirni ildizgacha tekshiradi. node:tls bu jarayonni qo'lda ko'rish imkonini beradi:
import tls from "node:tls";
const socket = tls.connect(
{ host: "cbu.uz", port: 443, servername: "cbu.uz" },
() => {
console.log(socket.getProtocol(), socket.authorized);
let cert = socket.getPeerCertificate(true);
const seen = new Set();
while (cert && !seen.has(cert.fingerprint256)) {
seen.add(cert.fingerprint256);
console.log(`${cert.subject.CN} ← ${cert.issuer.CN}`);
cert = cert.issuerCertificate;
}
socket.end();
},
);Biz ishga tushirgan chiqish (2026-10-23):
TLSv1.3 true
cbu.uz ← RapidSSL TLS RSA CA G1
RapidSSL TLS RSA CA G1 ← DigiCert Global Root G2
DigiCert Global Root G2 ← DigiCert Global Root G2O'qing pastdan yuqoriga:
- DigiCert Global Root G2 — ildiz sertifikat. O'zini o'zi imzolagan (
←dan keyin o'zi). U Node ichiga o'rnatilgan ishonchli ildizlar ro'yxatida bor. - RapidSSL TLS RSA CA G1 — oraliq CA: ildiz uni imzolagan.
- cbu.uz — saytning o'z sertifikati: oraliq CA imzolagan, 2026-yil 29-noyabrgacha amal qiladi.
getPeerCertificate(true) — zanjir bilan. seen to'plami kerak: ildizning issuerCertificate i o'ziga ishora qiladi, usiz sikl cheksiz bo'lardi. socket.authorized === true — Node zanjirni tekshirdi va ishondi. Kanon tajribasida ham xuddi shu: TLSv1.3, authorized: true, muddat 2026-11-29. Kanon issuer'ning tashkilot nomini yozgan (DigiCert Inc) — RapidSSL DigiCert'ning brendi, zid emas.
5.2 servername va xato
servername — SNI (Server Name Indication): mijoz "men qaysi saytga kelyapman" deb aytadi. Bitta IP'da yuzlab sayt bo'lishi mumkin, server shunga qarab sertifikat tanlaydi. Node esa sertifikatdagi nom servername ga mos kelishini tekshiradi. Kanon ataylab boshqa nom berdi:
const bad = tls.connect({
host: "cbu.uz",
port: 443,
servername: "boshqa.example",
});
bad.on("error", (e) => console.log("servername mos emas:", e.code));Kanon tajribasi (t26-net.txt):
servername mos emas: ERR_TLS_CERT_ALTNAME_INVALID"Sertifikatdagi muqobil nomlar (altnames) yaroqsiz" — sertifikat cbu.uz uchun, biz boshqa.example ni kutgan edik. Bu himoya: kimdir sizni boshqa serverga yo'naltirib, o'z (haqiqiy, lekin boshqa domenga berilgan) sertifikatini ko'rsatsa, ulanish shu yerda to'xtaydi.
6. Hujumchi nigohi: rejectUnauthorized: false
Ichki serverda o'z-o'zidan imzolangan sertifikat bo'lsa, fetch yoki tls.connect self-signed certificate ("o'zi imzolagan sertifikat") xatosini beradi. Internetdagi eng ko'p tavsiya etiladigan "yechim":
// ❌ butun tekshiruvni o'chiradi
tls.connect({ host, port, rejectUnauthorized: false });
// ❌ yanada yomoni — butun jarayon uchun
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";Hujumchi uchun bu sovg'a. Kafedagi ochiq Wi-Fi'da u o'zini router qilib ko'rsatadi va sizning ulanishingizni o'z serveriga yo'naltiradi (MITM — man-in-the-middle, "o'rtadagi odam"). Tekshiruv o'chiq bo'lsa, Node hujumchining sertifikatini ham qabul qiladi: shifr bor, lekin siz hujumchi bilan gaplashyapsiz. API kalitlari, parollar — hammasi unga.
To'g'ri yo'llar:
| Vaziyat | Yechim |
|---|---|
| Kompaniya ichki CA'si | NODE_EXTRA_CA_CERTS=/yo'l/ca.pem — o'sha CA qo'shimcha ishonchli bo'ladi |
| Bitta ulanish uchun o'z CA | tls.connect({ ca: fs.readFileSync("ca.pem") }) |
| Lokal ishlab chiqish | mkcert kabi vosita bilan lokal CA va sertifikat |
NODE_TLS_REJECT_UNAUTHORIZED=0 ni o'rnatsangiz, Node o'zi ham ogohlantiradi — bu ogohlantirishni hech qachon e'tiborsiz qoldirmang.
7. CLI qadami: holat yo'q — fetch hammasini qiladi
valyuta net, dns yoki tls ni to'g'ridan ishlatmaydi: fetch (Node ichidagi undici) DNS, TCP va TLS'ni o'zi bajaradi va to'g'ri sukut sozlamalar bilan (autoSelectFamily, sertifikat tekshiruvi). Qo'lda soket yozish CLI uchun faqat xato manbai bo'lardi. Shuning uchun bu darsning o'rni — kanon tajribasi (t26-net.txt) va ikkita amaliy saboq.
Birinchi saboq — xato nomini o'qish. valyuta ning xatolarini endi qatlam bo'yicha ajrata olasiz: ENOTFOUND — DNS, ECONNREFUSED — TCP (port yopiq), ERR_TLS_CERT_… — TLS, TimeoutError — timers darsidagi timeout.
Ikkinchi saboq — 127.0.0.1:9 siri. Timers darsida valyuta testlari va jonli sinov "ishlamaydigan server" sifatida http://127.0.0.1:9/ ni ishlatdi. Biz net va fetch ni yonma-yon sinadik (Node 24.21.0, Windows 11). Natija tarmoqqa emas, faqat shu kompyuterga bog'liq, shuning uchun har safar bir xil chiqadi:
import net from "node:net";
const sock = net.connect(9, "127.0.0.1");
sock.on("error", (e) => console.log("net 9:", e.code));
await new Promise((r) => sock.on("close", r));
for (const port of [9, 59999]) {
try {
await fetch(`http://127.0.0.1:${port}/`);
} catch (e) {
console.log(`fetch ${port}:`, e.cause?.code ?? e.cause?.message);
}
}Konsolda:
net 9: ECONNREFUSED
fetch 9: bad port
fetch 59999: ECONNREFUSEDnet 9-portga haqiqatan ulanishga urindi va rad oldi. fetch esa 9-portga umuman urinmadi. Fetch standartida xavfli portlar ro'yxati bor (9, 25 — SMTP, 6000 va boshqalar) va brauzer ham, Node ham ularga HTTP so'rov yubormaydi. Haqiqiy "port yopiq" — 59999 da. Ikkala holat ham valyuta uchun "tarmoq xatosi", lekin sababi boshqa. Bu farqni error.cause darsida kanon ham topadi. Bu darsda commit yo'q.
8. Ko'p uchraydigan xatolar
| Xato | Qatlam | Odatiy sabab |
|---|---|---|
ENOTFOUND |
DNS | domen xato yozilgan, internet yo'q |
ECONNREFUSED |
TCP | server ishlamayapti yoki boshqa portda/manzilda |
ECONNREFUSED ::1 |
TCP + IPv6 | server faqat 127.0.0.1 da, autoSelectFamily o'chiq |
ECONNRESET |
TCP | qarshi tomon ulanishni keskin uzdi |
ETIMEDOUT |
TCP | firewall paketlarni tashlab yuboryapti |
EADDRINUSE |
TCP (server) | port band — oldingi jarayon hali ishlayapti |
ERR_TLS_CERT_ALTNAME_INVALID |
TLS | sertifikat boshqa domenga |
self-signed certificate |
TLS | ichki CA — NODE_EXTRA_CA_CERTS |
9. Mashqlar
Mashqlar kurs/mashqlar/24/26-net-dns-tls/ da.
1-mashq (oson): qaysi qatlam?
getaddrinfo ENOTFOUND kurs.example—connect ECONNREFUSED 127.0.0.1:5432—ERR_TLS_CERT_ALTNAME_INVALID—hostsfaylini o'qiydigan funksiya —dns.- OS bo'sh port tanlasin —
server.listen()
Yechim
- DNS —
getaddrinfo— OS'ning nom aniqlash funksiyasi. - TCP — 5432 (PostgreSQL porti) da hech kim tinglamayapti.
- TLS — sertifikatdagi nom mos emas.
- lookup —
resolve*hostsni o'qimaydi. - 0 — tanlangan port
server.address().portda.
2-mashq (o'rta): uzunlik prefiksli xabarlar
Qator o'rniga boshqa chegaralash: har xabar oldidan uning uzunligi va : keladi — 5:salom. decode(chunks) funksiyasini yozing: bo'laklar massivini oladi (xabar bo'lak chegarasida bo'linishi mumkin) va to'liq xabarlar ro'yxatini qaytaradi. Sinang: ["5:sal", "om3:osh1", "0:ko'k choy!"].
Yechim
function decode(chunks) {
let buffer = "";
const messages = [];
for (const chunk of chunks) {
buffer += chunk;
while (true) {
const colon = buffer.indexOf(":");
if (colon === -1) break;
const length = Number(buffer.slice(0, colon));
const end = colon + 1 + length;
if (buffer.length < end) break; // xabar hali to'liq kelmadi
messages.push(buffer.slice(colon + 1, end));
buffer = buffer.slice(end);
}
}
return messages;
}
console.log(decode(["5:sal", "om3:osh1", "0:ko'k choy!"]));Konsolda:
[ 'salom', 'osh', "ko'k choy!" ]"10" uzunlik ham ikki bo'lakka bo'lindi ("1" va "0:…") — buffer ularni yig'di. Haqiqiy binar protokollarda uzunlik matn emas, 4 baytli son bo'ladi (Buffer darsida readUInt32BE bilan). Bu blok brauzerda ham ishlaydi.
3-mashq (qiyin): kurs serveri — jami summa
«Birinchi server» misolini kengaytiring: mijoz 100 usd ko'rinishidagi qator yuborsa, server 100 USD = 1190315 UZS (butun songa yaxlitlangan) qaytarsin; noto'g'ri qator — XATO. Har soketga "error" tinglovchisi qo'ying. Mijoz 100 usd, 2 eur, salom yuboradi.
Yechim
import net from "node:net";
import { createInterface } from "node:readline";
const RATES = { USD: 11903.15, EUR: 13372.4 };
function convert(line) {
const [amountText, codeText = ""] = line.trim().split(/\s+/);
const amount = Number(amountText);
const code = codeText.toUpperCase();
if (!Number.isFinite(amount) || !(code in RATES)) return "XATO";
const sum = Math.round(amount * RATES[code]);
return `${amount} ${code} = ${sum} UZS`;
}
const server = net.createServer((socket) => {
socket.on("error", () => {}); // bitta mijoz — butun server emas
const rl = createInterface({ input: socket });
rl.on("line", (line) => socket.write(convert(line) + "\n"));
});
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const client = net.connect(server.address().port, "127.0.0.1");
client.end("100 usd\n2 eur\nsalom\n");
let reply = "";
for await (const chunk of client) reply += chunk;
console.log(reply.trim());
server.close();Konsolda:
100 USD = 1190315 UZS
2 EUR = 26745 UZS
XATOconvert — toza funksiya, tarmoqsiz test qilsa bo'ladi; server faqat qatorlarni unga uzatadi. valyuta dagi bajar (buyruq.ts) ham xuddi shu g'oya: mantiq alohida, kirish-chiqish alohida.
4-mashq: CLI qadami — xatolarni qatlam bo'yicha ajrating
O'z valyuta ingizda uch xil noto'g'ri VALYUTA_API bilan ishga tushiring va har chiqishdagi "Ogohlantirish" qatorini yozib oling: http://yoq.invalid/, http://127.0.0.1:59999/, http://127.0.0.1:9/. Hozircha uchalasi ham bir xil "tarmoq xatosi" deydi — qaysi qatlamda yiqilganini o'zingiz yozing. Kod o'zgarmaydi.
Yechim
Hozirgi valyuta uchalasida: Qayta urinish …: CBU API: tarmoq xatosi, keyin fixture. Haqiqiy sabablar: yoq.invalid — DNS (ENOTFOUND; .invalid domeni hech qachon mavjud bo'lmaydi — standart); 59999 — TCP (ECONNREFUSED); 9 — hech qayerga ulanmadi, fetch uni "bad port" deb rad etdi. error.cause darsida valyuta bu sabablarni o'zi ko'rsatadigan bo'ladi.
10. Real ishda
- Ma'lumotlar bazasi ulanishi — PostgreSQL drayveri
net.connectbilan 5432-portga ulanadi, TLS ixtiyoriy. "Bazaga ulanmayapti" xatolari aynan shu darsdagi kodlar. - Redis, SMTP, MQTT — qatorli yoki uzunlik prefiksli TCP protokollari. Ularning Node drayverlari
net.Socketustida yozilgan. - Konteyner va
localhost— Docker ichidagi server127.0.0.1da tinglasa, tashqaridan ko'rinmaydi;0.0.0.0kerak. Bu deploy qismlarida qayta chiqadi. - Sertifikat muddati — monitoring skriptlari
tls.connect+getPeerCertificate().valid_tobilan "sertifikat 14 kunda tugaydi" ogohlantirishini yuboradi. - Intervyuda: "brauzerga URL yozilgandan keyin nima bo'ladi?" — DNS → TCP → TLS → HTTP; "
lookupvaresolvefarqi?".
Xulosa
net.createServer/net.connect— TCP soketlar; port 0 — OS tanlaydi; har soketga"error"tinglovchisi.- TCP — bayt oqimi, xabar chegarasi yo'q: qator (
readline), uzunlik prefiksi yoki sarlavha bilan chegaralang. dns.lookup— OS (hosts, kesh, thread pool);dns.resolve*— to'g'ridan DNS server va maxsus yozuvlar (MX).localhost→ avval::1;autoSelectFamily(sukuttrue) manzillarni navbat bilan sinaydi.tls.connectzanjirni ildizgacha tekshiradi;rejectUnauthorized: false— MITM'ga ochiq eshik, o'rnigaNODE_EXTRA_CA_CERTS.
Keyingi dars: EventEmitter asoslari — soket, readline, stream — hammasi hodisa chiqaradi. on, emit va "error" ning maxsusligi.
Manbalar
- Node.js hujjati — Net (
createServer,connect,autoSelectFamily,getDefaultAutoSelectFamily): https://nodejs.org/docs/latest-v24.x/api/net.html - Node.js hujjati — DNS ("Implementation considerations":
lookupvsresolve, thread pool;setDefaultResultOrder): https://nodejs.org/docs/latest-v24.x/api/dns.html - Node.js hujjati — TLS (
connect,getPeerCertificate,servername,rejectUnauthorized,NODE_EXTRA_CA_CERTS): https://nodejs.org/docs/latest-v24.x/api/tls.html - Fetch Standard — "bad port" ro'yxati: https://fetch.spec.whatwg.org/#port-blocking
- RFC 8305 — Happy Eyeballs Version 2: https://www.rfc-editor.org/rfc/rfc8305
- Kanon:
natijalar/tajriba/t26-net.txt(Node 24.21.0, Windows 11, 2026-10-23). IPv6/autoSelectFamily, DNS so'rovlari, TLS zanjiri, 9-port vaECONNRESET— biz ishga tushirdik (Node 24.21.0, Windows 11, 2026-10-23).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!