এই পর্বে যা শিখবেন
- একটি application-layer protocol ঠিক কী কী নির্ধারণ করে, আর RFC-র MUST, SHOULD, MAY কীভাবে পড়তে হয়
- Client-server, P2P আর hybrid গঠনের পার্থক্য — আর P2P ফাইল বিতরণের সময়ের পরীক্ষার হিসাব, প্রমাণ আর সংখ্যাসহ
- BitTorrent-এর torrent, tracker, DHT, chunk, rarest-first আর tit-for-tat — simulator চালিয়ে দেখা
- অ্যাপ কীভাবে socket দিয়ে transport-কে ডাকে, কোন অ্যাপ নেটওয়ার্কের কাছে কী চায়, আর protocol নকশার বড় সিদ্ধান্তগুলো
- নিজে একটি ছোট text protocol পড়া, parse করা আর C-তে loopback-এ চালানো; আর একটি ক্লিকের পুরো যাত্রা এক নজরে
১ · Application layer — যেখানে নেটওয়ার্ক মানুষের কাজে লাগে
এ পর্যন্ত পাঁচটি মডিউলে আমরা নিচ থেকে ওপরে উঠেছি: তারে সংকেত, frame, IP packet, routing, তারপর TCP আর UDP. কিন্তু কেউ “একটি TCP segment পাঠাতে” ইন্টারনেট ব্যবহার করেন না। মানুষ চান খবর পড়তে, বিকাশে টাকা পাঠাতে, ভিডিও কলে মায়ের সাথে কথা বলতে, অনলাইনে পরীক্ষার ফল দেখতে। এই কাজগুলো যে প্রোগ্রাম করে, তারা থাকে সবচেয়ে ওপরের স্তরে — application layer. পর্ব ০৩-এর TCP/IP মডেলে এটি পঞ্চম স্তর; OSI-র session, presentation আর application — তিনটির কাজই এখানে মিশে আছে।
একটা কথা শুরুতেই পরিষ্কার করা দরকার: application আর application-layer protocol এক জিনিস নয়। ওয়েব একটি application — এতে আছে ব্রাউজার, ওয়েব সার্ভার, HTML ফাইল, ছবি, আর তাদের মাঝে কথা বলার নিয়ম HTTP. ইমেইল একটি application — এতে আছে মেইল অ্যাপ, মেইল সার্ভার, mailbox, আর নিয়ম হিসেবে SMTP, IMAP. Protocol হলো পুরো ব্যবস্থার একটি অংশ — শুধু “তারে কী যাবে” সেই চুক্তি।
একটি protocol ঠিক কী কী ঠিক করে দেয়
পর্ব ০৩-এ দেখেছেন, protocol হলো দুই প্রান্তের একই স্তরের কথা বলার নিয়ম। Application স্তরে এই নিয়ম সাধারণত চারটি প্রশ্নের উত্তর দেয়:
বার্তার ধরন
কোন কোন বার্তা আছে — যেমন HTTP-তে request আর response; DNS-এ query আর reply; SMTP-তে HELO, MAIL, RCPT, DATA, QUIT-এর মতো command.
message typesগঠন (syntax)
বার্তায় কোন কোন ঘর, কোন ক্রমে, কীভাবে আলাদা — লাইন শেষে CRLF, শব্দের মাঝে একটি space, নাকি নির্দিষ্ট বাইটে নির্দিষ্ট মাপের সংখ্যা।
syntaxঅর্থ (semantics)
প্রতিটি ঘরের মানে কী — status 404 মানে “পাওয়া যায়নি”, DNS-এর একটি bit মানে “এটি উত্তর, প্রশ্ন নয়”.
semanticsসময় আর ক্রমের নিয়ম
কে আগে বলবে, কোন বার্তার পর কোনটি আসবে, উত্তর না এলে কতক্ষণ অপেক্ষা, ভুল বার্তা পেলে কী করতে হবে।
rules · state machineউপজেলা ভূমি অফিসে একটি নামজারির আবেদন ভাবুন। বার্তার ধরন — আবেদনপত্র, রসিদ, শুনানির নোটিশ। Syntax — নির্দিষ্ট ফরমে কোন ঘরে নাম, কোন ঘরে দাগ নম্বর। Semantics — “খতিয়ান নম্বর” ঘরের সংখ্যাটির মানে কী। নিয়ম — আগে আবেদন, তারপর ফি, তারপর শুনানি; কাগজ অসম্পূর্ণ হলে ফেরত। ফরমের কাগজ সাদা না হলুদ, ডাকে যাবে না হাতে — সেটা নিচের স্তরের ব্যাপার (transport). দুই পক্ষ একই নিয়ম মানলে তবেই কাজ হয়, অফিসার কে বা আবেদনকারী কোন জেলার, তাতে কিছু আসে যায় না।
খোলা বনাম মালিকানাধীন protocol
অনেক বড় protocol-এর পুরো নিয়ম প্রকাশ্যে লেখা থাকে RFC নামের দলিলে, যা প্রকাশ করে IETF: HTTP-র অর্থ RFC 9110-এ আর HTTP/1.1-এর বার্তার গঠন RFC 9112-এ, ইমেইল পাঠানোর SMTP RFC 5321-এ, DNS-এর মূল নিয়ম RFC 1034 আর 1035-এ। এগুলো খোলা (open) protocol — যে-কেউ পড়ে নিজের client বা সার্ভার বানাতে পারেন, আর তা অন্য সবার সাথে কাজ করবে; তাই Gmail থেকে একটি দেশি ISP-র মেইল সার্ভারে চিঠি যায়। অন্যদিকে অনেক মেসেজিং অ্যাপ বা অনলাইন গেমের নিয়ম শুধু সেই কোম্পানি জানে — মালিকানাধীন (proprietary) protocol. কোম্পানি দ্রুত বদলাতে পারে, কিন্তু অন্য কেউ যুক্ত হতে পারে না (ভাবনার প্রশ্ন ৫)।
অ্যাপ চলে শুধু প্রান্তে — আর সেটাই সবচেয়ে বড় সুবিধা
একটি নেটওয়ার্ক অ্যাপ লিখতে হয় শুধু end system-এর জন্য — ফোন, ল্যাপটপ, সার্ভার। পথের router-এ বা switch-এ কোনো অ্যাপ-কোড লিখতে হয় না; router তো network স্তরের ওপরে কিছু দেখেই না (পর্ব ১৫)। এর ফল বিশাল: কাউকে নতুন কোনো সেবা চালু করতে টেলিকম কোম্পানির অনুমতি বা নেটওয়ার্কের যন্ত্রপাতি বদলানোর অপেক্ষা করতে হয় না। দুটি কম্পিউটারে দুটি প্রোগ্রাম, মাঝে যেকোনো ইন্টারনেট — ব্যস। পর্ব ০৩-এর end-to-end নীতি-র সবচেয়ে বড় উপহার এটাই — ভাবনার প্রশ্ন ১-এ এর ইতিহাস।
Application-layer protocol = বার্তার ধরন + syntax + semantics + কখন-কী-করতে-হবে-র নিয়ম। নেটওয়ার্ক অ্যাপ চলে শুধু end system-এ, তাই নতুন অ্যাপের জন্য নেটওয়ার্ক বদলাতে হয় না।
২ · তিন রকম গঠন — client-server, peer-to-peer আর hybrid
পর্ব ০২-এ দুটি গঠনের মূল পার্থক্য দেখেছেন: client-server-এ একটি server সেবা দেয় আর অনেক client সেবা নেয়; peer-to-peer-এ সবাই একসাথে দেয় আর নেয়। এখানে দেখব অ্যাপ-নকশাকারীর চোখে — খরচ, ঝুঁকি আর বড় হলে কী ঘটে।
Client-server: সবসময় চালু সার্ভার
Client-server গঠনে সার্ভারের তিনটি বৈশিষ্ট্য: সে সবসময় চালু (always-on), তার স্থায়ী, পরিচিত ঠিকানা থাকে (একটি নাম, DNS দিয়ে IP), আর সে নিজে কারও কাছে যায় না — client আগে যোগাযোগ শুরু করে। ওয়েব, ইমেইল, ব্যাংকিং অ্যাপ, অনলাইন ভর্তি আবেদন — সবই এই গঠনের।
জনপ্রিয় সেবায় একটি সার্ভার যথেষ্ট নয়। তখন হাজার হাজার সার্ভার রাখা হয় বিশাল data center-এ, আর সামনে load balancer অনুরোধ ভাগ করে দেয় (পর্ব ৫২)। বিদ্যুৎ, ঠান্ডা রাখা আর bandwidth-এর পুরো খরচ সেবাদাতার।
Peer-to-peer: ব্যবহারকারীরাই সার্ভার
P2P গঠনে সবসময়-চালু সার্ভারের ওপর ভরসা কম বা একেবারেই নেই। সাধারণ ব্যবহারকারীর যন্ত্র — peer — সরাসরি একে অপরের সাথে কথা বলে। কেউ একটি ফাইল ডাউনলোড করার সময়ই অন্যদের সেই ফাইলের অংশ আপলোড করে। সবচেয়ে বড় সুবিধা self-scalability: নতুন peer এলে সে চাহিদা বাড়ায়, কিন্তু সাথে নিজের আপলোড-ক্ষমতাও নিয়ে আসে। অংশ ৩-এ এর গাণিতিক রূপ দেখবেন।
কিন্তু P2P-র কঠিন দিকও আছে। Peer-রা আসে-যায় (কারও লোডশেডিং, কেউ ল্যাপটপ বন্ধ করলেন), IP বদলায়, অনেকে NAT-এর পেছনে (পর্ব ১৯)। বাসার ইন্টারনেটে আপলোড গতি প্রায়ই ডাউনলোডের চেয়ে কম। আর নিরাপত্তা: অচেনা peer-এর দেওয়া ডেটা বিশ্বাস করা যায় কি না — তাই BitTorrent প্রতিটি chunk-এর hash মিলিয়ে নেয়।
Hybrid: খোঁজার কাজ কেন্দ্রে, ভারী কাজ প্রান্তে
বাস্তবের অনেক ব্যবস্থাই মিশ্র। ভিডিও কলের অ্যাপে কে অনলাইন আছেন, কার ঠিকানা কী — এসব থাকে কেন্দ্রীয় সার্ভারে; কিন্তু সম্ভব হলে কণ্ঠ আর ভিডিও সরাসরি দুই ফোনের মধ্যে যায় (WebRTC-এর মতো প্রযুক্তি, পর্ব ৪০)। পুরোনো Napster (১৯৯৯) গানের তালিকা রাখত কেন্দ্রীয় সার্ভারে, কিন্তু ফাইল আসত ব্যবহারকারীদের কম্পিউটার থেকে। আর CDN (পর্ব ৩৮) উল্টো দিক থেকে মিশ্রণ: সার্ভারই, কিন্তু ব্যবহারকারীর কাছাকাছি হাজার জায়গায় ছড়ানো।
| বৈশিষ্ট্য | Client-server | Peer-to-peer | Hybrid |
|---|---|---|---|
| সবসময়-চালু সার্ভার | হ্যাঁ, কেন্দ্রে | না (বা প্রায় না) | খোঁজা আর নিয়ন্ত্রণের জন্য হ্যাঁ |
| ব্যবহারকারী বাড়লে ক্ষমতা | সার্ভার বাড়াতে হয় (টাকা) | নিজে থেকেই বাড়ে | ভারী অংশে নিজে থেকে বাড়ে |
| নিয়ন্ত্রণ, নিরাপত্তা, হিসাব | সহজ — এক জায়গায় | কঠিন — অচেনা peer | মাঝামাঝি |
| NAT আর আসা-যাওয়ার সমস্যা | কম | বেশি | সার্ভার সাহায্য করে (যেমন NAT পেরোতে) |
| উদাহরণ | ওয়েব, ইমেইল, ব্যাংকিং অ্যাপ | BitTorrent, কিছু blockchain নেটওয়ার্ক | ভিডিও কল (WebRTC), Napster, tracker-সহ BitTorrent |
একটি সূক্ষ্ম কথা: P2P অ্যাপেও প্রতিটি যোগাযোগের মুহূর্তে একটি পক্ষ client আর অন্যটি server. যে peer অনুরোধ পাঠাল, সে ওই আলাপে client; যে উত্তর দিল, সে server. তাই “client” আর “server” শব্দ দুটি দুই অর্থে চলে — পুরো অ্যাপের গঠন বোঝাতে, আর একটি নির্দিষ্ট আলাপে কে শুরু করল তা বোঝাতে।
৩ · P2P কেন বড় হয় — ফাইল বিতরণের সময়ের হিসাব
ধরুন একটি বড় ফাইল — একটি Linux ইনস্টলেশন ইমেজ বা একটি সফটওয়্যার আপডেট — N জন মানুষের কাছে পৌঁছাতে হবে। সবাই পুরো ফাইল পেলে কাজ শেষ। এই সময়কে বলে distribution time. প্রশ্ন: client-server আর P2P-তে এই সময়ের সর্বনিম্ন মান কত? বিশ্ববিদ্যালয় আর চাকরির পরীক্ষায় এটি খুব প্রচলিত হিসাব।
মডেল আর চিহ্ন
F— ফাইলের আকার (bit)N— কতজন peer ফাইলটি চায়u_s— সার্ভারের আপলোড গতি;u_i— i-তম peer-এর আপলোড গতিd_i— i-তম peer-এর ডাউনলোড গতি;d_min— সবচেয়ে ধীর peer-এর ডাউনলোড গতি
ধরে নেওয়া হয় ইন্টারনেটের মাঝখানে কোনো ভিড় নেই — বাধা শুধু প্রান্তের link-এ (access link), আর ডেটাকে পানির মতো যত সূক্ষ্মভাবে খুশি ভাগ করা যায় — একে বলে fluid model.
Client-server: দুটি নিচের সীমা
(ক) সার্ভারের আপলোড: N জনের প্রত্যেককে আলাদা একটি পূর্ণ কপি পাঠাতে হবে, অর্থাৎ সার্ভারকে মোট NF bit তুলতে হবে। গতি u_s, তাই কমপক্ষে NF/u_s সময়। (খ) সবচেয়ে ধীর client: তাকে F bit নামাতে হবে, তার গতি d_min, তাই কমপক্ষে F/d_min সময়। দুটি শর্তই মানতে হবে, তাই সময় অন্তত দুটির বড়টি। আর সার্ভার যদি সব client-কে min(u_s/N, d_min) হারে একসাথে পাঠায়, ঠিক এই সময়েই কাজ শেষ হয় — তাই এটিই সর্বনিম্ন:
D_cs = max( N·F / u_s , F / d_min )
D_P2P = max( F / u_s , F / d_min , N·F / (u_s + Σ u_i) )
P2P: তিনটি নিচের সীমা
(ক) শুরুতে ফাইলটি শুধু সার্ভারের কাছে, তাই অন্তত একটি পূর্ণ কপি সার্ভারকে তুলতেই হবে: F/u_s. (খ) সবচেয়ে ধীর peer-কে F bit নামাতে হবে: F/d_min. (গ) মোট N জনের কাছে মোট NF bit পৌঁছাতে হবে, আর পুরো ব্যবস্থার মোট আপলোড-ক্ষমতা সার্ভার আর সব peer মিলিয়ে u_s + Σu_i — তাই কমপক্ষে NF/(u_s + Σu_i). এই তিনটির বড়টিই নিচের সীমা। Fluid model-এ একটি চতুর বণ্টন (সার্ভার প্রতিটি peer-কে আলাদা অংশ দেয়, আর প্রতিটি peer নিজের অংশ বাকি সবাইকে পাঠায়) দিয়ে দেখানো যায় যে এই সীমাতেও পৌঁছানো সম্ভব — তাই বাস্তব বিশ্লেষণে এটিকেই সর্বনিম্ন সময় ধরা হয়।
সবচেয়ে জরুরি পর্যবেক্ষণ — N বাড়লে কী হয়
D_cs-এর প্রথম পদ NF/u_s — N-এর সাথে সরলরেখায় বাড়ে; হাজার জন হলে হাজার গুণ। D_P2P-এর তৃতীয় পদে সব peer-এর আপলোড গতি সমান u ধরলে NF/(u_s + Nu). N বড় হলে এটি এগিয়ে যায় F/u-এর দিকে, কিন্তু কখনো পেরোয় না — ব্যবহারকারী যতই বাড়ুক, P2P-র সময় একটি ছাদের নিচে থাকে। এটিই self-scalability-র গাণিতিক রূপ: প্রতিটি নতুন peer চাহিদা আনে F, ক্ষমতাও আনে u.
একটি পুরো numerical (পরীক্ষার ধাঁচে)
একটি ১ GB ফাইল, মানে F = ৮,০০০ Mbit (১ GB = ৮,০০০ Mbit ধরে, দশমিক একক)। সার্ভারের আপলোড u_s = ১০০ Mbps, সবচেয়ে ধীর peer-এর ডাউনলোড d_min = ২০ Mbps, প্রতিটি peer-এর আপলোড u = ৫ Mbps, আর N = ১০০.
- Client-server: NF/u_s = ১০০ × ৮,০০০ / ১০০ = ৮,০০০ সেকেন্ড; F/d_min = ৮,০০০ / ২০ = ৪০০ সেকেন্ড। D_cs = max(৮,০০০, ৪০০) = ৮,০০০ সেকেন্ড ≈ ১৩৩.৩ মিনিট.
- P2P: F/u_s = ৮০ সেকেন্ড; F/d_min = ৪০০ সেকেন্ড; NF/(u_s + Nu) = ৮,০০,০০০ / (১০০ + ৫০০) = ৮,০০,০০০ / ৬০০ ≈ ১,৩৩৩.৩ সেকেন্ড। D_P2P = ≈ ১,৩৩৩.৩ সেকেন্ড ≈ ২২.২ মিনিট.
- তুলনা: P2P প্রায় ৬ গুণ দ্রুত। আর N যত বাড়বে, পার্থক্য তত বাড়বে — P2P-র সময়ের ছাদ F/u = ৮,০০০/৫ = ১,৬০০ সেকেন্ড ≈ ২৬.৭ মিনিট.
নিচের ছবিতে দুটি অক্ষই logarithmic (প্রতিটি দাগে ১০ গুণ), N ১০ থেকে ১,০০০. Client-server-এর রেখা সোজা ওপরে উঠছে; P2P-র রেখাগুলো চ্যাপ্টা হয়ে নিজ নিজ ছাদের দিকে যাচ্ছে।
বিতরণের সময় বনাম peer-এর সংখ্যা (F = ৮,০০০ Mbit, u_s = ১০০, d_min = ২০ Mbps)
Log-log plot: client-server grows linearly with N; P2P flattens towards F/u
নিজে চালিয়ে দেখুন: বিতরণ-সময়ের calculator
নিচের প্রোগ্রাম এই দুই সূত্রে কয়েকটি N আর তিন রকম peer-আপলোড গতির (১, ৫, ২০ Mbps) জন্য সময় ছাপে, তারপর client-server কোথা থেকে পিছিয়ে পড়ে আর P2P-র ছাদ কোথায় তা দেখায়।
// Minimum distribution time: client-server vs P2P (fluid model, rates in Mbit/s).
const F = 8000; // file size: 1 GB = 8000 Mbit
const us = 100; // server upload rate
const dmin = 20; // slowest peer's download rate
const Dcs = N => Math.max(N * F / us, F / dmin);
const Dp2p = (N, u) => Math.max(F / us, F / dmin, N * F / (us + N * u));
const t = s => (s / 60).toFixed(1).padStart(9) + " min";
console.log("N".padStart(5) + ["D_cs", "D_P2P u=1", "D_P2P u=5", "D_P2P u=20"]
.map(h => h.padStart(13)).join(""));
for (const N of [1, 5, 10, 50, 100, 200, 500, 1000]) {
console.log(String(N).padStart(5) + t(Dcs(N)) + t(Dp2p(N, 1)) + t(Dp2p(N, 5)) + t(Dp2p(N, 20)));
}
// Crossover: the first N where client-server becomes slower than P2P (u = 5)
let N = 1;
while (Dcs(N) <= Dp2p(N, 5)) N++;
console.log(`\nu=5: client-server is slower from N = ${N}` +
` (D_cs ${Dcs(N)} s vs D_P2P ${Dp2p(N, 5).toFixed(0)} s)`);
console.log(`client-server grows without limit: +${F / us} s per extra peer`);
for (const u of [1, 5, 20])
console.log(`P2P limit as N grows (u=${u}): F/u = ${F / u} s = ${t(F / u).trim()}`);আউটপুট:
N D_cs D_P2P u=1 D_P2P u=5 D_P2P u=20
1 6.7 min 6.7 min 6.7 min 6.7 min
5 6.7 min 6.7 min 6.7 min 6.7 min
10 13.3 min 12.1 min 8.9 min 6.7 min
50 66.7 min 44.4 min 19.0 min 6.7 min
100 133.3 min 66.7 min 22.2 min 6.7 min
200 266.7 min 88.9 min 24.2 min 6.7 min
500 666.7 min 111.1 min 25.6 min 6.7 min
1000 1333.3 min 121.2 min 26.1 min 6.7 min
u=5: client-server is slower from N = 6 (D_cs 480 s vs D_P2P 400 s)
client-server grows without limit: +80 s per extra peer
P2P limit as N grows (u=1): F/u = 8000 s = 133.3 min
P2P limit as N grows (u=5): F/u = 1600 s = 26.7 min
P2P limit as N grows (u=20): F/u = 400 s = 6.7 min
প্রথম দুই সারিতে (N = ১ আর ৫) সবগুলো সময় ৬.৭ মিনিট — এখানে বাধা সবচেয়ে ধীর peer-এর ডাউনলোড, F/d_min = ৪০০ সেকেন্ড; সার্ভার যথেষ্ট দ্রুত। N = ৬ থেকে client-server-এর সময় NF/u_s সেই সীমা পেরোয় (৬ × ৮০ = ৪৮০ সেকেন্ড), আর তারপর প্রতিটি নতুন peer ঠিক ৮০ সেকেন্ড যোগ করে — ১,০০০ জনে ১,৩৩৩ মিনিট। এটাই সাধারণ নিয়ম: client-server-এর রেখা বাঁকে যখন N > u_s/d_min = ১০০/২০ = ৫.
P2P-র কলামগুলো দেখুন: u = ৫-এ ১,০০০ জনেও মাত্র ২৬.১ মিনিট, আর শেষ লাইনের ছাদ ২৬.৭ মিনিট। u = ১-এ ছাদ অনেক উঁচু (১৩৩.৩ মিনিট) — peer যত কম আপলোড করে, P2P-র সুবিধা তত কম। আর u = ২০ হলে peer-এর আপলোড তার নিজের ডাউনলোডের সমান, তাই প্রতিটি N-এ সময় সেই ৬.৭ মিনিটে আটকে থাকে — বাধা আবার সবচেয়ে ধীর ডাউনলোড।
৪ · BitTorrent — torrent, tracker, chunk আর ভাগাভাগির নিয়ম
অংশ ৩-এর হিসাব বাস্তবে সবচেয়ে সফলভাবে কাজে লাগিয়েছে BitTorrent — Bram Cohen ২০০১ সালে এর নকশা করেন। আজও Linux distribution-এর ইমেজ আর Internet Archive-এর মতো সংগ্রহশালার বড় ফাইল বিতরণে এটি বৈধভাবে ব্যবহৃত হয়। (যে ফাইল বিতরণের অধিকার আপনার নেই, তা যেকোনো পদ্ধতিতেই শেয়ার করা বেআইনি — protocol নিরপেক্ষ, দায় ব্যবহারকারীর।)
মূল উপাদানগুলো
- Torrent আর swarm: একটি নির্দিষ্ট ফাইল (বা ফাইলগুচ্ছ) বিনিময়ে অংশ নেওয়া সব peer মিলে একটি swarm. যার কাছে পুরো ফাইল আছে, তাকে বলে seeder; যে এখনো নামাচ্ছে, সে leecher.
- .torrent ফাইল বা magnet link: এতে থাকে ফাইলের নাম, আকার, chunk-এর মাপ, প্রতিটি chunk-এর hash, আর কোথায় peer খুঁজতে হবে। ফাইলের মূল পরিচয় একটি hash — “info hash”.
- Chunk (piece): ফাইল সমান মাপের টুকরোয় ভাগ — মাপ সাধারণত কয়েকশো KiB থেকে কয়েক MiB. প্রতিটি chunk পেয়ে peer hash মিলিয়ে দেখে — নষ্ট বা নকল হলে বাদ।
- Tracker: একটি সার্ভার, যে শুধু জানে কোন torrent-এ এখন কারা আছে। নতুন peer tracker-কে জানায় “আমি এলাম”, আর বদলে কিছু peer-এর IP:port-এর তালিকা পায়। Tracker ফাইলের কোনো অংশ রাখে না।
- DHT: tracker ছাড়াও peer খোঁজা যায় distributed hash table দিয়ে — লাখো peer মিলে “কে কোন torrent-এ আছে” তালিকাটি ভাগ করে রাখে। Hash table-এর ধারণা DSA কোর্সের hash table পর্বে দেখতে পারেন।
কোন chunk আগে চাইবেন — rarest first
একজন peer-এর হাতে কিছু chunk আছে, বাকিগুলো নেই। প্রতিবেশীদের কাছে কোনটি কতজনের আছে, তা সে জানে (peer-রা নিজেদের মধ্যে “আমার কাছে কোন কোন chunk আছে” বিনিময় করে)। নিয়ম: যে chunk swarm-এ সবচেয়ে কম কপিতে আছে, সেটি আগে চাওয়া — rarest first. কারণ: বিরল chunk-এর মালিক চলে গেলে সেটি swarm থেকে হারিয়ে যেতে পারে, তখন কেউ ফাইল শেষ করতে পারবে না। আগে বিরলগুলো ছড়িয়ে দিলে সব chunk-এর কপি দ্রুত সমান হয়, আর প্রত্যেক peer অন্যদের দেওয়ার মতো কিছু হাতে পায়।
কাকে দেবেন — tit-for-tat
প্রত্যেক peer-এর আপলোড-ক্ষমতা সীমিত, তাই সে সবাইকে একসাথে দেয় না। BitTorrent-এর মূল নকশায় একজন peer মোটামুটি প্রতি ১০ সেকেন্ডে মেপে দেখে কে তাকে সবচেয়ে দ্রুত দিচ্ছে, আর সেরা চারজনকে পাঠায় — তাদের “unchoke” করে, বাকিদের আপাতত “choke” করে রাখে। এর নাম tit-for-tat — যে দেয়, তাকেই আগে দেওয়া। আর প্রতি ৩০ সেকেন্ডে একজন এলোমেলো peer-কে বিনা শর্তে দেওয়া হয় — optimistic unchoke — যাতে নতুন peer শুরু করতে পারে আর হয়তো আরও ভালো সঙ্গী খুঁজে পাওয়া যায়। ফলে যারা শুধু নেয়, দেয় না (free-rider), তারা ধীরে ধীরে কম পায়। (সংখ্যাগুলো মূল client-এর; আধুনিক client-ভেদে কিছুটা আলাদা হতে পারে।)
পাড়ার কয়েকজন বন্ধু একটি মোটা প্রশ্নব্যাংক ফটোকপি করছেন; মূল বই একজনের কাছে, আর তিনি দুদিন পর গ্রামে চলে যাবেন। বুদ্ধিমানের কাজ: যে অধ্যায়ের কপি এখনো কারও কাছে নেই, সেটি আগে মূল বই থেকে করিয়ে নেওয়া — সাধারণ অধ্যায় পরে বন্ধুদের কাছেই পাওয়া যাবে। আর যে বন্ধু আপনাকে পাতা দিচ্ছেন, আপনিও আগে তাঁকেই দেন।
নিচের stepper আর simulator একটি ছোট swarm দেখায়: seeder S-এর কাছে পাঁচটি chunk (০–৪) সবই আছে; চারজন peer A, B, C, D-র কাছে কিছু কিছু। প্রতি রাউন্ডে প্রত্যেকে সর্বোচ্চ একটি chunk আপলোড আর একটি ডাউনলোড করতে পারে, আর S রাউন্ড ২-এর পর চলে যায়। Bit-স্ট্রিং “10100” মানে chunk ০ আর ২ আছে।
| কোন রাউন্ড | |
| বিনিময় | |
| A B C D | |
| peer-দের কাছে কপি (chunk ০–৪) |
- শুরু। Peer-দের কাছে কপির সংখ্যা: chunk ০ তিনটি, ১ আর ২ দুটি করে, ৩ একটি, আর ৪ একটিও নয় — শুধু seeder S-এর কাছে। প্রত্যেক peer এই গণনা দেখে নিজের না-থাকা chunk-গুলো বিরলতা অনুযায়ী সাজায়।
- রাউন্ড ১. A-র নেই ১, ৩, ৪ — সবচেয়ে বিরল ৪, তাই সে S থেকে ৪ নেয়। B-ও ৪ চাইত, কিন্তু S ব্যস্ত; তার পরের পছন্দ ১ (দুই কপি), C থেকে। C নেয় ৩ (এক কপি) B থেকে, D নেয় ২ A থেকে। একই রাউন্ডে প্রত্যেকে একজনকে দিল, একজনের কাছ থেকে নিল।
- রাউন্ড ২ — S-এর শেষ রাউন্ড। এখন ৪-এর একটি কপি A-র কাছে, তাই B সেটি A থেকে নেয়, আর C নেয় S থেকে। A নেয় ৩ (B থেকে), D নেয় ৩ (C থেকে)। রাউন্ড শেষে S চলে যায় — কিন্তু তার আগেই প্রতিটি chunk-এর অন্তত তিনটি কপি peer-দের হাতে।
- রাউন্ড ৩. শুধু peer-রা নিজেরা: A পায় ১ (B), B পায় ০ (A), C পায় ২ (D), D পায় ৪ (C). চারজনই সম্পূর্ণ। Seeder ছাড়াই swarm বাকি কাজ সেরে ফেলল।
- তুলনা — সবাই নিচের নম্বর আগে চাইলে। একই শুরু, কিন্তু প্রত্যেকে আগে সবচেয়ে ছোট নম্বরের chunk চায়। S-এর দুই রাউন্ডের আপলোড খরচ হলো chunk ২ আর ৩-এ, যেগুলো peer-দের কাছেও ছিল। Chunk ৪ কেউ চায়নি, আর S চলে যাওয়ায় সেটি হারিয়ে গেল — চারজনই “11110”-এ আটকে, চিরকালের জন্য।
// Swarm: seed S (all 5 chunks) + peers A-D. Every round each node UPLOADS at
// most one chunk and each peer DOWNLOADS at most one. S LEAVES after round 2.
// A peer tries its missing chunks in order of preference and takes the first one
// that some free node can give (other peers first, the seed last).
function run(rarestFirst) {
const have = { S: "11111", A: "10100", B: "00110", C: "11000", D: "11000" };
const peers = ["A", "B", "C", "D"], ids = [0, 1, 2, 3, 4];
for (let round = 1; round <= 5; round++) {
const copies = ids.map(c => peers.filter(p => have[p][c] === "1").length);
const busy = new Set(round > 2 ? ["S"] : []), got = [];
for (const p of peers) {
const want = ids.filter(c => have[p][c] === "0")
.sort((x, y) => rarestFirst ? copies[x] - copies[y] || x - y : x - y);
for (const c of want) {
const from = [...peers.filter(q => q !== p), "S"]
.find(q => have[q][c] === "1" && !busy.has(q));
if (from) { busy.add(from); got.push(`${p}<-${c}(${from})`); break; }
}
}
for (const g of got) { // all transfers of a round end together
const p = g[0], c = +g[3];
have[p] = have[p].slice(0, c) + "1" + have[p].slice(c + 1);
}
console.log(`round ${round}: ${got.join(" ").padEnd(36)}| ` +
peers.map(p => p + ":" + have[p]).join(" "));
if (peers.every(p => !have[p].includes("0"))) return console.log(" -> everyone complete");
}
console.log(" -> stuck: chunk 4 left with the seed, no peer can finish");
}
console.log("== rarest first =="); run(true);
console.log("== in order (lowest chunk first) =="); run(false);আউটপুট:
== rarest first ==
round 1: A<-4(S) B<-1(C) C<-3(B) D<-2(A) | A:10101 B:01110 C:11010 D:11100
round 2: A<-3(B) B<-4(A) C<-4(S) D<-3(C) | A:10111 B:01111 C:11011 D:11110
round 3: A<-1(B) B<-0(A) C<-2(D) D<-4(C) | A:11111 B:11111 C:11111 D:11111
-> everyone complete
== in order (lowest chunk first) ==
round 1: A<-1(C) B<-0(A) C<-2(B) D<-2(S) | A:11100 B:10110 C:11100 D:11100
round 2: A<-3(B) B<-1(A) C<-3(S) | A:11110 B:11110 C:11110 D:11100
round 3: D<-3(A) | A:11110 B:11110 C:11110 D:11110
round 4: | A:11110 B:11110 C:11110 D:11110
round 5: | A:11110 B:11110 C:11110 D:11110
-> stuck: chunk 4 left with the seed, no peer can finish
প্রতিটি লেখা যেমন A<-4(S) মানে “A chunk ৪ পেল S থেকে”. Rarest-first-এ রাউন্ড ১-এই A seeder-এর কাছ থেকে একমাত্র অনুপস্থিত chunk ৪ তুলে নেয়, আর রাউন্ড ২-এ C-ও নেয় — S চলে যাওয়ার আগেই ৪-এর তিনটি কপি swarm-এ। তিন রাউন্ডে সবাই সম্পূর্ণ।
In-order নিয়মে রাউন্ড ১-এ D chunk ২ নেয় S থেকে (যা A আর B-র কাছেও ছিল, শুধু তারা তখন ব্যস্ত), রাউন্ড ২-এ C নেয় ৩ S থেকে — seeder-এর মূল্যবান আপলোড খরচ হলো সাধারণ chunk-এ। রাউন্ড ৩-এর পর কোনো বিনিময়ই হয় না: সবার কাছে 11110, আর chunk ৪ গেছে S-এর সাথে। বাস্তব swarm অনেক বড়, কিন্তু সমস্যাটা একই — এজন্য BitTorrent client সাধারণত rarest-first-কেই ডিফল্ট রাখে।
৫ · Process, socket আর ঠিকানা — অ্যাপ কীভাবে transport-কে ডাকে
নেটওয়ার্কে আসলে কথা বলে দুটি process — চলমান প্রোগ্রাম (process কী, তা অপারেটিং সিস্টেম কোর্সের process পর্বে আছে)। আলাদা কম্পিউটারের দুই process কথা বলে নেটওয়ার্কে বার্তা আদান-প্রদান করে। যে process যোগাযোগ শুরু করে সে client process, যে অপেক্ষা করে সে server process.
Process আর নেটওয়ার্কের মাঝের দরজা হলো socket — পর্ব ২৭-এ বিস্তারিত দেখেছেন। দরজার এপাশ অ্যাপের হাতে — কী লিখবেন, কখন লিখবেন; ওপাশ kernel-এর হাতে — retransmission, congestion control. অ্যাপের নিয়ন্ত্রণ তাই মূলত কোন transport বাছবেন আর কিছু প্যারামিটার, যেমন buffer-এর মাপ। Socket API-র পুরো প্রোগ্রামিং মডিউল ৭-এ (পর্ব ৪১–৪৫)।
Process-এর ঠিকানা: IP + port
চিঠি পাঠাতে লাগে বাড়ির ঠিকানা আর প্রাপকের নাম। একটি process-কে বার্তা পাঠাতেও দুটি জিনিস লাগে: যে host-এ সে চলছে তার IP ঠিকানা, আর সেই host-এর ভেতরে তার socket-এর port নম্বর। ওয়েব সার্ভার সাধারণত TCP 443 (HTTPS) বা 80 (HTTP)-এ, মেইল সার্ভার 25-এ, DNS সার্ভার 53-এ শোনে — পরিচিত port-এর তালিকা পর্ব ২৭-এ। শুধু IP যথেষ্ট নয়, কারণ একই host-এ একসাথে অনেক process নেটওয়ার্ক ব্যবহার করে।
অ্যাপ নেটওয়ার্কের কাছে কী চায় — আর কোন protocol কী বাছে
পর্ব ২৭-এ চারটি চাহিদা দেখেছেন: ডেটার নির্ভুলতা (data integrity), throughput, সময় (timing) আর নিরাপত্তা। এখানে বাস্তব অ্যাপগুলোকে এই চার চাহিদার মাপকাঠিতে সাজাই — application-layer নকশার প্রথম সিদ্ধান্ত এখান থেকেই আসে:
| অ্যাপ | ডেটা হারানো চলে? | Throughput | সময়ের চাপ | App protocol → transport |
|---|---|---|---|---|
| ফাইল ডাউনলোড, সফটওয়্যার আপডেট | না | যা পাওয়া যায় (elastic) | নেই | HTTP → TCP বা QUIC; BitTorrent → TCP (বা uTP, UDP-র ওপর) |
| ইমেইল | না | elastic | নেই | SMTP, IMAP → TCP |
| ওয়েব পাতা, ব্যাংকিং API | না | elastic | আছে, তবে নরম (দ্রুত হলে ভালো) | HTTP/1.1, HTTP/2 → TCP; HTTP/3 → QUIC |
| ভিডিও কল, ইন্টারনেট ফোন | কিছুটা চলে | কণ্ঠে কয়েক থেকে কয়েক শত kbps, ভিডিওতে কয়েক Mbps পর্যন্ত | কড়া — কয়েকশো মিলিসেকেন্ড | RTP → সাধারণত UDP |
| রেকর্ড করা ভিডিও স্ট্রিমিং | কিছুটা চলে | নির্দিষ্ট মাত্রা দরকার | মাঝারি — কয়েক সেকেন্ডের buffer | HTTP (DASH, HLS) → TCP বা QUIC |
| অনলাইন গেম | কিছুটা চলে | কম, কয়েক থেকে কয়েক দশ kbps | কড়া | প্রায়ই নিজস্ব protocol → UDP |
| নাম থেকে ঠিকানা (DNS) | না, তবে অ্যাপ নিজেই আবার জিজ্ঞেস করে | খুব কম | আছে | DNS → সাধারণত UDP, বড় উত্তরে TCP |
আর নিরাপত্তা? আজ প্রায় প্রতিটি সারিতে একই উত্তর: encryption আর সার্ভার যাচাই লাগবে। TCP বা UDP নিজে তা দেয় না; অ্যাপ সেটি পায় TCP-র ওপর TLS বসিয়ে (HTTPS, IMAPS, SMTP-এর STARTTLS), বা QUIC ব্যবহার করে, যার ভেতরেই TLS 1.3 আছে (পর্ব ৩৩)। TLS-কে কখনো কখনো “স্তর ৪.৫” বলা হয় — প্রযুক্তিগতভাবে এটি application-এর অংশ হিসেবে চলে, অ্যাপের লাইব্রেরিতে, OS-এর transport-এ নয়। বিস্তারিত পর্ব ৪৮-এ।
৬ · Protocol নকশার বড় সিদ্ধান্তগুলো
নতুন protocol বানাতে বা চেনা protocol বুঝতে কয়েকটি মৌলিক প্রশ্নের উত্তর লাগে — পরের ছয়টি পর্বের প্রতিটি protocol-কে এই মাপকাঠিতে চিনতে পারবেন।
Text বনাম binary
Text protocol-এ বার্তা মানুষের পড়ার মতো লেখা — সাধারণত ASCII অক্ষরে, প্রতিটি লাইন শেষে CRLF — carriage return আর line feed, দুটি বাইট। HTTP/1.1, SMTP, POP3, IMAP, FTP, SIP — সব text. সুবিধা: একটি সাধারণ টার্মিনাল দিয়েই কথা বলা যায়, ভুল খোঁজা সহজ, নতুন header যোগ করা সহজ। অসুবিধা: আকার বড়, আর parse করতে বেশি কাজ — সংখ্যাকে অক্ষর থেকে রূপান্তর, লাইন কোথায় শেষ খোঁজা, বাড়তি space বা ছোট-বড় হাতের অক্ষরের মতো অস্পষ্টতা সামলানো।
Binary protocol-এ প্রতিটি ঘর নির্দিষ্ট বাইটে, নির্দিষ্ট মাপে: DNS-এর ১২ বাইটের header, HTTP/2-এর ৯ বাইটের frame header, QUIC, TLS, MQTT. সুবিধা: ছোট, দ্রুত, অস্পষ্টতা কম, আর একটি সংযোগে অনেক স্রোত পাশাপাশি চালানোর মতো কাজ (HTTP/2-এর multiplexing) সহজে করা যায়। অসুবিধা: পড়তে Wireshark-এর মতো টুল লাগে। HTTP/2 কেন text ছেড়ে binary হলো, তা পর্ব ৩৭-এ।
Text (SMTP, উদাহরণ) Binary (DNS header-এর প্রথম ৪ বাইট, hex)
C: MAIL FROM:<rahim@example.com> 1a 2b 01 00
S: 250 OK └─ ID=0x1a2b, flags=0x0100 (প্রশ্ন, recursion চাই)
Stateless বনাম stateful
একটি stateless protocol-এ সার্ভার আগের অনুরোধ মনে রাখে না — প্রতিটি অনুরোধ নিজেই সম্পূর্ণ। HTTP এমন: সার্ভারের কাছে আপনার দ্বিতীয় অনুরোধ প্রথমটির সাথে protocol-এর দিক থেকে সম্পর্কহীন। DNS query-ও তাই। সুবিধা: যেকোনো সার্ভার যেকোনো অনুরোধের উত্তর দিতে পারে, তাই হাজার সার্ভারে ভাগ করা সহজ। “লগইন করা আছি” মনে রাখতে HTTP-র ওপর cookie বসিয়ে অ্যাপ নিজে অবস্থা রাখে (পর্ব ৩৬)।
Stateful protocol-এ সংযোগ বা session-এর একটি অবস্থা থাকে, আর একই command-এর মানে সেই অবস্থার ওপর নির্ভর করে। SMTP-তে DATA পাঠানো যায় শুধু MAIL FROM আর RCPT TO-এর পরে; IMAP-এ আগে একটি mailbox SELECT করলে তবেই তার চিঠি পড়া যায়; FTP মনে রাখে আপনি কোন ফোল্ডারে আছেন। খরচ: সার্ভারকে প্রতিটি client-এর অবস্থা রাখতে হয়।
একটি ফাঁদ: “stateless” মানে protocol-এর কথা, সার্ভারের নয়। নিচের KV/1 protocol-এ প্রতিটি অনুরোধের syntax স্বাধীন, কিন্তু সার্ভার একটি ডেটার ভান্ডার রাখে — তার অ্যাপের অবস্থা আছে। ডেটাবেস সার্ভার অবস্থা না রাখলে তো কোনো কাজেরই নয়!
Push বনাম pull
যে পক্ষ ডেটার মালিক, সে নিজে পাঠালে push; যে চায়, সে গিয়ে আনলে pull. HTTP মূলত pull — ব্রাউজার চায়, সার্ভার দেয়। ইমেইলে দুটোই: আপনার মেইল সার্ভার প্রাপকের মেইল সার্ভারে SMTP দিয়ে চিঠি push করে, আর প্রাপক নিজের মেইল অ্যাপে IMAP দিয়ে তা pull করেন (পর্ব ৩৯)। মোবাইলের notification-এ সার্ভার push করে — এজন্য ফোন একটি দীর্ঘস্থায়ী সংযোগ খুলে রাখে, কারণ NAT-এর পেছনের ফোনে বাইরে থেকে সংযোগ খোলা যায় না।
যোগাযোগের তিন ধাঁচ
Request-response
Client একটি অনুরোধ পাঠায়, server একটি উত্তর দেয়। HTTP, DNS, ডেটাবেস query. সরল, কিন্তু নতুন খবর জানতে client-কে বারবার জিজ্ঞেস করতে হয়।
request-responsePublish-subscribe
প্রকাশক একটি বিষয়ে (topic) বার্তা দেয় একটি মধ্যস্থ broker-এর কাছে; যারা সেই বিষয়ে আগ্রহী (subscriber), broker তাদের পৌঁছে দেয়। প্রকাশক জানেই না কে পড়ছে।
publish-subscribe · MQTTStreaming
একটি দীর্ঘ সংযোগে একটানা ডেটা — লাইভ ভিডিও, শেয়ারবাজারের দাম, চ্যাট। WebSocket বা gRPC-র stream; বিস্তারিত পর্ব ৪০-এ।
streamingPublish-subscribe-এর সবচেয়ে পরিচিত উদাহরণ MQTT — IoT-র জন্য বানানো হালকা binary protocol, সাধারণত TCP port 1883-এ চলে, TLS-সহ 8883-এ। ধরুন একটি মাছের খামারে পুকুরের পানির তাপমাত্রা আর অক্সিজেন মাপার সেন্সর: সেন্সরটি প্রতি মিনিটে farm/pond1/oxygen topic-এ একটি ছোট বার্তা publish করে। খামারির ফোনের অ্যাপ, একটি সতর্কবার্তা পাঠানোর সার্ভিস আর একটি ডেটাবেস — তিনজনই এই topic-এ subscribe করে আছে। সেন্সরকে তাদের কারও ঠিকানা জানতে হয় না; নতুন একজন subscriber যোগ করতে সেন্সরের কোড বদলাতে হয় না। দুর্বল সংযোগের কথা ভেবে MQTT-তে ছোট header আর বার্তা পৌঁছানোর তিনটি নিশ্চয়তা-স্তর আছে।
HTTP-র ওপর API-র চার ধাঁচ — এক নজরে
আজকের অ্যাপের বেশিরভাগ যোগাযোগ চলে API দিয়ে — এক প্রোগ্রাম আরেক প্রোগ্রামকে ডাকে। বেশিরভাগই HTTP-র ওপরে বসানো, কিন্তু ধাঁচ আলাদা:
| ধাঁচ | মূল ধারণা | ডেটার রূপ | কোথায় ভালো |
|---|---|---|---|
| REST | সবকিছু একটি resource, URL দিয়ে চেনা; HTTP-র GET, POST, PUT, DELETE দিয়ে কাজ; প্রতিটি অনুরোধ স্বয়ংসম্পূর্ণ (stateless) | সাধারণত JSON (text) | সাধারণ ওয়েব ও মোবাইল API — পর্ব ৩৬ |
| gRPC | দূরের function ডাকা, যেন নিজের প্রোগ্রামের function; HTTP/2-এর ওপর, stream-ও চলে | Protocol Buffers (binary) | ডেটা সেন্টারের ভেতরে microservice-দের মধ্যে দ্রুত যোগাযোগ |
| GraphQL | একটি endpoint; client নিজেই একটি query লিখে বলে কোন কোন ঘর চাই, সার্ভার ঠিক ততটুকু দেয় | JSON | এক পাতায় অনেক রকম ডেটা লাগে এমন অ্যাপ — কম অনুরোধে বেশি তথ্য |
| WebSocket | শুরু HTTP দিয়ে, তারপর সংযোগটি “upgrade” হয়ে দুই দিকেই যেকোনো সময় বার্তা পাঠানোর নালি (RFC 6455) | text বা binary frame | চ্যাট, লাইভ স্কোর, সহযোগী সম্পাদনা — পর্ব ৪০ |
একটি বড় অ্যাপ প্রায়ই সবগুলোই ব্যবহার করে — বাইরে REST বা GraphQL, ভেতরে gRPC, লাইভ আপডেটে WebSocket.
৭ · একটি protocol নিজে পড়া, parse করা আর চালানো
RFC পড়ার কৌশল — MUST, SHOULD, MAY
RFC-র ভাষা প্রথমে শুকনো লাগে, কিন্তু কয়েকটি শব্দ চিনলে পড়া অনেক সহজ। RFC 2119 (১৯৯৭) কিছু শব্দের নির্দিষ্ট মানে ঠিক করে দেয়, আর RFC 8174 (২০১৭) স্পষ্ট করে যে এই বিশেষ মানে শুধু তখনই, যখন শব্দগুলো বড় হাতের অক্ষরে লেখা:
- MUST / REQUIRED / SHALL — বাধ্যতামূলক। না মানলে আপনার implementation এই protocol-এর নয়। (MUST NOT — কোনো অবস্থাতেই নয়।)
- SHOULD / RECOMMENDED — জোরালো সুপারিশ; বিশেষ, ভালোভাবে বোঝা কারণ থাকলে না মানা যায়, কিন্তু ফল বুঝে। (SHOULD NOT একই রকম।)
- MAY / OPTIONAL — সত্যিই ঐচ্ছিক। অন্য পক্ষকে এমনভাবে লিখতে হবে যাতে আপনি করলেও, না করলেও কাজ চলে।
পড়ার অভ্যাস: আগে Abstract আর “Terminology”; বার্তার গঠন থাকে ABNF ব্যাকরণে বা বাক্স-আঁকা diagram-এ; “Security Considerations” বাদ নয়; আর rfc-editor.org-এ দেখে নিন RFC-টি “Obsoleted by” কি না।
একটি খেলনা protocol: KV/1
অনুশীলনের জন্য এই পর্বে একটি ছোট key-value protocol বানাই — Redis-এর মতো ডেটাবেসের সরল “inline” command-এর ধাঁচে। নিচে তার “RFC” — মাত্র কয়েক লাইন, কিন্তু ঠিক বাস্তবের মতো ভাষায়:
KV/1 — a toy key-value protocol over TCP (for learning only)
1. A request is one line of ASCII text. Every line MUST end with CRLF (0x0D 0x0A).
2. Words MUST be separated by exactly one SP (0x20).
3. Commands: SET key value | GET key | DEL key | QUIT
Servers MUST accept command names in any letter case. Keys are case-sensitive.
4. A key MUST match [A-Za-z0-9_]{1,15}. A value MUST NOT contain SP or CRLF.
5. The server MUST send exactly one reply line per request, in order:
SET -> OK | GET -> VALUE v or NOT_FOUND | DEL -> DELETED or NOT_FOUND
QUIT -> BYE, then the server closes the connection | anything else -> ERR reason
6. A client SHOULD send QUIT before closing. A server MAY close an idle connection.
অংশ ১-এর চারটি উপাদানই এখানে আছে: বার্তার ধরন (চারটি command), syntax (লাইন, CRLF, একটি space), semantics (NOT_FOUND মানে “এই key নেই”) আর নিয়ম (প্রতিটি অনুরোধে ঠিক একটি উত্তর, ক্রমমতো)। আর আছে অবস্থা — সার্ভারের ভান্ডার।
Byte-স্রোত থেকে বার্তা — framing
অনেকে প্রথমবার এখানে ভুল করেন: TCP দেয় byte-স্রোত, বার্তা নয় (পর্ব ২৭)। Client দুবার write() করলে সার্ভার একবারে দুটো লাইন পেতে পারে, বা একটি লাইনের অর্ধেক। তাই protocol-কেই বলে দিতে হয় একটি বার্তা কোথায় শেষ — একে বলে framing. KV/1-এ framing হলো CRLF; HTTP/1.1-এ header-এর শেষে একটি ফাঁকা লাইন আর body-র দৈর্ঘ্য Content-Length-এ; binary protocol-এ সাধারণত শুরুতে একটি দৈর্ঘ্যের ঘর। নিচের parser বাইটগুলো ইচ্ছা করে এলোমেলো টুকরোয় পায়।
// KV/1 - a toy line-based text protocol (like a tiny Redis "inline" format).
// Syntax: COMMAND SP key [SP value] CRLF. Semantics + state: a server-side store.
const store = new Map(); // the server's STATE survives between requests
const ARITY = { SET: 3, GET: 2, DEL: 2, QUIT: 1 };
function handle(line) {
const words = line.split(" ");
const cmd = words[0].toUpperCase(); // spec: command names are case-insensitive
if (!(cmd in ARITY)) return "ERR unknown command"; // syntax: bad verb
if (words.length !== ARITY[cmd]) return "ERR wrong number of arguments";
const [, key, value] = words;
if (!/^[A-Za-z0-9_]{1,15}$/.test(key ?? "x")) return "ERR bad key";
if (cmd === "SET") { store.set(key, value); return "OK"; } // semantics
if (cmd === "GET") return store.has(key) ? "VALUE " + store.get(key) : "NOT_FOUND";
if (cmd === "DEL") return store.delete(key) ? "DELETED" : "NOT_FOUND";
return "BYE";
}
// Bytes arrive from a TCP byte stream in arbitrary pieces: frame them by CRLF.
const chunks = ["SET city Dhaka\r\nGE", "T city\r\nget city\r\nSET x 1\r\n",
"PUT x 1\r\nDEL city\r\nGET city\r\nSET roll 42", "\r\nQUIT\r\n"];
let buf = "";
chunks.forEach((c, i) => {
buf += c;
console.log(`-- chunk ${i + 1} arrives (${c.length} bytes)`);
let at;
while ((at = buf.indexOf("\r\n")) >= 0) { // one complete line = one request
const line = buf.slice(0, at); buf = buf.slice(at + 2);
console.log(`C: ${line.padEnd(16)} S: ${handle(line)}`);
}
if (buf) console.log(` (waiting: "${buf}" has no CRLF yet)`);
});
console.log("final state:", JSON.stringify(Object.fromEntries(store)));আউটপুট:
-- chunk 1 arrives (18 bytes)
C: SET city Dhaka S: OK
(waiting: "GE" has no CRLF yet)
-- chunk 2 arrives (28 bytes)
C: GET city S: VALUE Dhaka
C: get city S: VALUE Dhaka
C: SET x 1 S: ERR wrong number of arguments
-- chunk 3 arrives (40 bytes)
C: PUT x 1 S: ERR unknown command
C: DEL city S: DELETED
C: GET city S: NOT_FOUND
(waiting: "SET roll 42" has no CRLF yet)
-- chunk 4 arrives (8 bytes)
C: SET roll 42 S: OK
C: QUIT S: BYE
final state: {"roll":"42"}
Framing: প্রথম টুকরোর শেষে “GE” এসেছে, কিন্তু CRLF নেই — parser অপেক্ষা করে, পরের টুকরোর “T city” জুড়ে পুরো GET city বানায়। একইভাবে SET roll 42 দুই টুকরোয় ভাগ হয়ে এসেছে। আর দ্বিতীয় টুকরোয় একসাথে তিনটি অনুরোধ — তিনটিই আলাদা করে উত্তর পেল। Syntax: SET x 1-এ দুটি space, তাই শব্দ ভাগ করলে একটি ফাঁকা শব্দ আসে আর শব্দের সংখ্যা মেলে না — “wrong number of arguments”; PUT অচেনা command. Semantics আর spec-এর নিয়ম: ছোট হাতের get city-ও কাজ করল, কারণ spec-এর MUST নিয়ম বলেছে command যেকোনো case-এ গ্রহণ করতে হবে। অবস্থা: DEL-এর পর একই GET city-এর উত্তর বদলে NOT_FOUND — একই বার্তা, ভিন্ন অবস্থা, ভিন্ন উত্তর; শেষে ভান্ডারে শুধু roll.
এবার একই protocol-এ একটি পুরো আলাপ ধাপে ধাপে — বাঁ দিকে তারে যাওয়া বাইট, ডান দিকে সার্ভারের ভান্ডার। নিচের C প্রোগ্রাম ঠিক এই আলাপটিই চালাবে।
| Client পাঠাল | |
| Server-এর parse | |
| Server উত্তর দিল | |
| সার্ভারের ভান্ডার |
- প্রথম অনুরোধ। Client তিনটি শব্দ আর CRLF পাঠায়। সার্ভার CRLF পর্যন্ত একটি লাইন পড়ে, তিন ভাগ করে, দেখে key নেই — নতুন ঘর বানিয়ে
city = Dhakaরাখে, উত্তরOK. - পড়া।
GET city— দুই শব্দ, syntax ঠিক। ভান্ডারে key আছে, উত্তরVALUE Dhaka. সার্ভার কিছু বদলায়নি। - বদলানো। একই key-তে আবার SET — নতুন ঘর নয়, পুরোনো মান বদলে
Khulna. এটাই SET-এর semantics: না থাকলে রাখা, থাকলে বদলানো। - আবার পড়া। একই অনুরোধ
GET city, কিন্তু এবার উত্তরVALUE Khulna— উত্তর নির্ভর করে সার্ভারের অবস্থার ওপর। - মুছে ফেলা।
DEL city— key পাওয়া গেল, মুছে উত্তরDELETED. ভান্ডার এখন খালি। - নেই এমন key.
GET cityতৃতীয়বার — এবারNOT_FOUND. ভুল নয়, একটি বৈধ উত্তর: “এমন কিছু নেই”. - অচেনা command.
PUTspec-এ নেই। সার্ভার সংযোগ কেটে দেয় না, নিয়ম মেনেERRদিয়ে শুরু হওয়া একটি উত্তর দেয় — প্রতিটি অনুরোধে ঠিক একটি উত্তর দেওয়া বাধ্যতামূলক। - বিদায়।
QUIT-এর উত্তরBYE, তারপর সার্ভার সংযোগ বন্ধ করে। Client নিয়ম (SHOULD) মেনে বিদায় জানিয়ে গেল।
আসল TCP-তে: fork করা client আর server, loopback-এ
নিচের C প্রোগ্রাম 127.0.0.1-এ একটি TCP socket খোলে (port 0 মানে kernel নিজেই একটি খালি port বেছে দেবে), তারপর fork() করে: child process হয় KV/1 সার্ভার, parent হয় client. Client আটটি অনুরোধ পাঠায়, প্রতিটির পর এক লাইনের উত্তর পড়ে, আর পুরো আলাপ ছাপে। ছাপার কাজ শুধু parent করে, তাই আউটপুটের ক্রম প্রতিবার একই। (Socket ফাংশনের বিস্তারিত মডিউল ৭-এ।)
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#define IS(x) (!strcasecmp(cmd, x)) /* command names: any letter case */
static void serve(int c) { /* KV/1 server: the store is its STATE */
char k[8][16], v[8][32], line[128], cmd[8], a[16], b[32]; int n = 0; FILE *in = fdopen(c, "r");
while (fgets(line, sizeof line, in)) { /* one line = one request */
cmd[0] = 0; int f = sscanf(line, "%7s %15s %31s", cmd, a, b), i = 0;
while (f > 1 && i < n && strcmp(k[i], a)) i++; /* look the key up */
if (IS("SET") && f == 3 && i < 8) { n += (i == n); strcpy(k[i], a); strcpy(v[i], b); dprintf(c, "OK\r\n"); }
else if (IS("GET") && f == 2 && i < n) dprintf(c, "VALUE %s\r\n", v[i]);
else if (IS("DEL") && f == 2 && i < n) { /* move the last entry into the hole */
if (i < --n) { strcpy(k[i], k[n]); strcpy(v[i], v[n]); } dprintf(c, "DELETED\r\n"); }
else if ((IS("GET") || IS("DEL")) && f == 2) dprintf(c, "NOT_FOUND\r\n");
else if (IS("QUIT") && f == 1) { dprintf(c, "BYE\r\n"); break; }
else dprintf(c, "ERR bad request\r\n");
}
}
int main(void) {
const char *req[] = {"SET city Dhaka", "GET city", "SET city Khulna", "GET city",
"DEL city", "GET city", "PUT x 1", "QUIT"};
struct sockaddr_in sa = {.sin_family = AF_INET}; socklen_t len = sizeof sa; char line[128];
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* 127.0.0.1, port 0 = any */
int ls = socket(AF_INET, SOCK_STREAM, 0); bind(ls, (struct sockaddr *)&sa, sizeof sa); listen(ls, 1);
getsockname(ls, (struct sockaddr *)&sa, &len); fflush(stdout); /* learn the free port */
if (fork() == 0) { serve(accept(ls, NULL, NULL)); _exit(0); } /* child = server */
int s = socket(AF_INET, SOCK_STREAM, 0); /* parent = client */
connect(s, (struct sockaddr *)&sa, sizeof sa); FILE *in = fdopen(s, "r");
for (int i = 0; i < 8 && dprintf(s, "%s\r\n", req[i]) > 0 && fgets(line, sizeof line, in); i++) {
line[strcspn(line, "\r\n")] = 0; printf("C: %-16s S: %s\n", req[i], line); } /* one reply each */
wait(NULL); return 0;
}আউটপুট:
C: SET city Dhaka S: OK
C: GET city S: VALUE Dhaka
C: SET city Khulna S: OK
C: GET city S: VALUE Khulna
C: DEL city S: DELETED
C: GET city S: NOT_FOUND
C: PUT x 1 S: ERR bad request
C: QUIT S: BYE
উত্তরগুলো stepper আর JS parser-এর সাথে হুবহু মেলে — শুধু অচেনা command-এর ব্যাখ্যার লেখা আলাদা: এখানে ERR bad request, JS-এ ERR unknown command. দুটিই বৈধ, কারণ spec শুধু বলেছে উত্তর ERR দিয়ে শুরু হবে, কারণের লেখা নয়। সার্ভার strcasecmp() দিয়ে command-এর case উপেক্ষা করে, কিন্তু key তুলনায় strcmp() — spec অনুযায়ী key case-sensitive. আর sscanf("%15s") লম্বা key-কে নীরবে ছেঁটে ফেলে, যা spec-এর নিয়ম ৪ ভাঙে — খেলনা সার্ভারের একটি ইচ্ছাকৃত দুর্বলতা; বাস্তব সার্ভারে এমন ক্ষেত্রে ERR ফেরত দেওয়া উচিত। সবকিছু loopback-এ, বাইরের কোনো নেটওয়ার্ক লাগেনি।
৮ · একটি ক্লিকের পেছনে — URL লিখে Enter চাপলে কী হয়
নেটওয়ার্কিং ইন্টারভিউর সবচেয়ে বিখ্যাত প্রশ্ন: “ব্রাউজারে একটি ঠিকানা লিখে Enter চাপলে কী কী ঘটে?” এই মডিউলের প্রতিটি পর্ব তার একেকটি ধাপ; এখানে শুধু মানচিত্র। ধরা যাক আপনি লিখলেন https://www.example.com/news, আর হিসাবের সুবিধার জন্য ধরি: resolver পর্যন্ত DNS-এর উত্তর আসতে ২০ ms, আর সার্ভার পর্যন্ত RTT ৩০ ms, সার্ভারের নিজের কাজে ১০ ms.
- URL ভাঙা
https · 443ব্রাউজার - DNS
নাম → IPপর্ব ৩৫ - TCP
handshakeপর্ব ২৯ - TLS
key + certificateপর্ব ৪৮ - HTTP
GET /newsপর্ব ৩৬–৩৭ - Cache / CDN
HIT?পর্ব ৩৮ - Rendering
HTML → পাতাব্রাউজার
| ধাপ | |
| জানা গেল | |
| মোট সময় (আনুমানিক) |
- URL ভাঙা। ব্রাউজার URL-কে টুকরো করে: scheme
https(তাই ডিফল্ট port 443 আর এনক্রিপশন লাগবে), hostwww.example.com, path/news. আগে নিজের cache-এ দেখে — পাতাটি কি সম্প্রতি আনা হয়েছে আর এখনো তাজা? - DNS. নাম থেকে IP: ব্রাউজার আর OS-এর cache-এ না পেলে প্রশ্ন যায় resolver-এর কাছে, যে দরকারে root, TLD আর authoritative সার্ভার ঘুরে উত্তর আনে। ধরা যাক ২০ ms-এ উত্তর এল:
203.0.113.80. পুরো যাত্রা পর্ব ৩৫-এ। - TCP handshake. SYN, SYN-ACK, ACK — এক RTT, ৩০ ms. মোট ৫০ ms. (কম্পিউটারের প্রথম hop পর্যন্ত পৌঁছাতে ARP বা IPv6-এর neighbor discovery আর default gateway লাগে — মডিউল ৩.) Handshake-এর বিস্তারিত পর্ব ২৯-এ।
- TLS. TLS 1.3-এ আরও এক RTT: দুই পক্ষ একটি গোপন key-তে একমত হয়, আর সার্ভার certificate দেখায় — ব্রাউজার যাচাই করে নামটি সত্যিই www.example.com কি না। মোট ৮০ ms. বিস্তারিত পর্ব ৪৮-এ।
- HTTP. এনক্রিপ্টেড নালিতে
GET /newsযায়, আর ৩০ ms RTT + ১০ ms সার্ভারের কাজ পরে আসে200 OKআর HTML. মোট ১২০ ms. HTTP/1.1-এর বার্তা পর্ব ৩৬-এ, HTTP/2-এর multiplexing পর্ব ৩৭-এ। - Cache আর CDN. আসলে 203.0.113.80 হয়তো মূল সার্ভার নয় — কাছের কোনো শহরে রাখা একটি CDN edge, যার কাছে পাতাটির কপি ছিল — একে বলে HIT. না থাকলে (MISS) edge মূল সার্ভার থেকে এনে দিত, আরও সময় লাগত। কাছে রাখার এই কৌশল পর্ব ৩৮-এ।
- Rendering. ব্রাউজার HTML পড়ে দেখে আরও লাগবে — CSS, ছবি, JavaScript. সেগুলোর অনুরোধ যায় একই সংযোগে (HTTP/2-এ পাশাপাশি)। HTTP/3 হলে TCP আর TLS-এর দুই RTT একটিতে মিশে যায় (QUIC, পর্ব ৩৩), তাই এই হিসাবে HTML আসত ৯০ ms-এ। লাইভ আপডেট লাগলে WebSocket খোলে — পর্ব ৪০.
লক্ষ করুন, এই ১২০ ms-এর বেশিরভাগই RTT-র গুণিতক — ব্যান্ডউইথ নয়, দূরত্ব আর ধাপের সংখ্যা। তাই আধুনিক protocol ধাপ কমায় (TLS 1.3, QUIC, DNS cache), আর CDN দূরত্ব কমায়। ইন্টারভিউতে ভালো উত্তর মানে ঠিক এই stepper-এর তিনটি সারি: ধাপের ক্রম, প্রতিটিতে কোন protocol, আর কোথায় সময় যায়। পূর্ণ ইন্টারভিউ-রূপ পর্ব ৬২-এ।
আরও গভীরে: Linux-এ অ্যাপ আর transport-এর সীমানা আক্ষরিক অর্থেই একটি system call-এর সীমানা — প্রতিটি send() বা recv() user space থেকে kernel-এ যায়, তাই অনেক ছোট বার্তার protocol-এ এই খরচ কমাতে বড় সার্ভার একসাথে অনেক বার্তা পাঠায় বা io_uring-এর মতো ব্যবস্থা ব্যবহার করে। QUIC এই সীমানা সরিয়ে নির্ভরযোগ্যতা আর congestion control-কে অ্যাপের লাইব্রেরিতে নিয়ে এসেছে — application আর transport-এর রেখা আজ আগের মতো পরিষ্কার নয়। BitTorrent-এর DHT (Mainline DHT) Kademlia-র XOR-দূরত্ব ব্যবহার করে, যাতে কয়েক লাখ বা তার বেশি node-এর মধ্যেও একটি key খুঁজতে মোটামুটি log N সংখ্যক ধাপ লাগে।
পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:
- Client-server আর P2P-র বিতরণ-সময়ের সূত্র লিখুন। — D_cs = max(NF/u_s, F/d_min); D_P2P = max(F/u_s, F/d_min, NF/(u_s + Σu_i)). প্রথমটি N-এর সাথে সরলরেখায় বাড়ে, দ্বিতীয়টি F/u-এর দিকে সীমাবদ্ধ থাকে।
- একটি process-কে নেটওয়ার্কে কীভাবে চেনা হয়? — host-এর IP ঠিকানা আর সেই host-এ তার socket-এর port নম্বর দিয়ে।
- HTTP stateless হলে লগইন কীভাবে মনে থাকে? — protocol মনে রাখে না; সার্ভার একটি cookie দেয়, ব্রাউজার প্রতিটি অনুরোধে তা ফেরত পাঠায় — অবস্থা রাখে অ্যাপ।
- BitTorrent-এ rarest-first আর tit-for-tat কেন? — প্রথমটি বিরল chunk হারানো ঠেকায় ও সব chunk সমানভাবে ছড়ায়; দ্বিতীয়টি যারা দেয় তাদের পুরস্কৃত করে free-rider কমায়।
- URL লিখে Enter চাপলে কী হয়? — URL বিশ্লেষণ → DNS → TCP (বা QUIC) → TLS → HTTP → cache/CDN → rendering আর বাকি resource.
৯ · AI-এর যুগে application protocol নকশা
REST না gRPC, P2P-র অঙ্ক, একটি chat protocol-এর নকশা — AI এসবে দ্রুত, গোছানো উত্তর দেয়, কিন্তু কিছু চেনা ভুলও করে:
| AI-এর ভুল | কেন ভুল | কীভাবে ধরবেন |
|---|---|---|
| P2P সূত্রে F/u_s বা F/d_min পদ বাদ দেওয়া, বা Mbit আর MB গুলিয়ে ৮ গুণ ভুল | তিনটি নিচের সীমার যেকোনোটি প্রধান হতে পারে; একক না মেলালে উত্তর বদলে যায় | অংশ ৩-এর calculator-এ নিজের সংখ্যা বসিয়ে মেলান; প্রতিটি পদ আলাদা করে লিখুন |
| “HTTP stateful, কারণ cookie আছে” বা “UDP-র ওপর বলে HTTP/3 অনির্ভরযোগ্য” | Cookie অ্যাপের অবস্থা, protocol-এর নয়; QUIC নিজেই নির্ভরযোগ্যতা দেয় | RFC 9110 (HTTP-র অর্থ) আর RFC 9000 (QUIC)-এর ভূমিকা পড়ুন |
| বানানো বা পুরোনো RFC নম্বর — যেমন HTTP/1.1-এর জন্য শুধু RFC 2616 | ২৬১৬ বহু আগেই বাতিল; এখন RFC 9110–9112 | rfc-editor.org-এ শিরোনাম আর “Obsoleted by” দেখুন |
| নিজের বানানো protocol-এ framing না রাখা — “এক write = এক বার্তা” ধরে নেওয়া | TCP byte-স্রোত; বার্তা ভেঙে বা জোড়া লেগে আসতে পারে | অংশ ৭-এর মতো এলোমেলো টুকরোয় ডেটা দিয়ে parser পরীক্ষা করুন |
| P2P চালাতে “firewall বন্ধ করুন” বা “router-এ সব port খুলে দিন” | পুরো যন্ত্র আক্রমণের সামনে চলে যায় | শুধু অ্যাপের নির্দিষ্ট একটি port, শুধু দরকারে; বাকিটা বন্ধ রাখুন |
পুরোনো টুল আর কমান্ড — netstat, ifconfig-কে একমাত্র পথ বলা | আধুনিক Linux-এ ss, ip; অনেক সিস্টেমে পুরোনোগুলো থাকেই না | man ss, man ip; পর্ব ০৬ |
নতুন protocol বা API নকশায় AI-এর সাহায্য নিলে প্রয়োজন আর যাচাইয়ের শর্ত স্পষ্ট করে দিন:
AI-এর protocol পরামর্শ মানার আগে — চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১ওয়েব কেন এত দ্রুত সারা পৃথিবীতে ছড়াল, অথচ টেলিফোন নেটওয়ার্কে নতুন সেবা আনতে বছরের পর বছর লাগত? “অ্যাপ চলে শুধু প্রান্তে” নীতি দিয়ে ব্যাখ্যা করুন।
পুরোনো টেলিফোন নেটওয়ার্কে বুদ্ধি ছিল নেটওয়ার্কের ভেতরে। হাতের ফোনটি প্রায় কিছুই করত না; সংযোগ, বিল, call forwarding, caller ID — সবই হতো exchange-এর switch-এ। ফলে নতুন কোনো সেবা চালু করতে টেলিফোন কোম্পানিকে নিজের যন্ত্র বদলাতে হতো, মান নির্ধারণ সংস্থায় একমত হতে হতো, আর তারপর দেশে দেশে বসাতে হতো। বাইরের কেউ চাইলেও নতুন সেবা আনতে পারতেন না — নেটওয়ার্ক ছিল তাঁদের হাতের বাইরে।
ইন্টারনেট উল্টো পথ নিয়েছিল। IP শুধু packet পৌঁছায়, আর তার ওপরের সব বুদ্ধি থাকে প্রান্তের কম্পিউটারে — পর্ব ০৩-এর end-to-end নীতি। ১৯৮৯–১৯৯১ সালে CERN-এ Tim Berners-Lee যখন ওয়েব বানালেন, তাঁর লাগল একটি ব্রাউজার, একটি সার্ভার প্রোগ্রাম, HTML আর HTTP-র একটি সরল নিয়ম। কোনো router বদলাতে হয়নি, কোনো ISP-র অনুমতি নিতে হয়নি। যে-কেউ সার্ভারটি নামিয়ে নিজের কম্পিউটারে চালাতে পারতেন, আর পরদিন থেকে সারা পৃথিবী তাঁর পাতা দেখতে পারত। CERN ১৯৯৩ সালে ওয়েবের সফটওয়্যার সবার জন্য বিনা রয়্যালটিতে উন্মুক্ত করে দেয়, আর তার পরের কয়েক বছরে ওয়েবসাইটের সংখ্যা বিস্ফোরকভাবে বাড়ে।
একই কথা পরের প্রায় প্রতিটি বড় উদ্ভাবনের জন্য সত্য: ইমেইল সেবা, ভিডিও কল, অনলাইন গেম, মোবাইল ব্যাংকিং — কোনোটির জন্যই নেটওয়ার্কের মাঝখান বদলাতে হয়নি। কেউ কেউ একে বলেন “permissionless innovation” — অনুমতি ছাড়া উদ্ভাবন। এর মূল্যও আছে: নেটওয়ার্ক কোনো গুণমানের নিশ্চয়তা দেয় না, তাই অ্যাপকেই ভিড়, ক্ষতি আর নিরাপত্তা সামলাতে হয়; আর middlebox-গুলো যখন ভেতরে উঁকি দিতে শুরু করল, তখন নতুন transport চালানো কঠিন হয়ে গেল — পর্ব ২৭-এর ossification.
মূল উপলব্ধি: নেটওয়ার্কের মাঝখান সরল আর অ্যাপ প্রান্তে থাকায় নতুন সেবার জন্য কারও অনুমতি লাগেনি — ওয়েব আর অ্যাপ-বিস্ফোরণের পেছনে প্রযুক্তির চেয়েও বড় ভূমিকা এই নকশা-দর্শনের।
প্র ০২Napster থেকে BitTorrent — P2P ফাইল শেয়ারিংয়ের নকশা কীভাবে বদলেছে, আর আজ বড় কোম্পানিগুলো কেন P2P-র বদলে CDN বেশি ব্যবহার করে?
১৯৯৯ সালের Napster ছিল আসলে hybrid: কার কাছে কোন গান আছে, সেই তালিকা থাকত কোম্পানির কেন্দ্রীয় সার্ভারে, আর ফাইল আসত সরাসরি ব্যবহারকারীর কম্পিউটার থেকে। প্রযুক্তিগতভাবে সরল, কিন্তু কেন্দ্রীয় সূচিটিই হয়ে গেল দুর্বলতা — কপিরাইট মামলায় আদালতের নির্দেশে সেই সার্ভার বন্ধ হতেই পুরো ব্যবস্থা থেমে গেল (২০০১)। এরপর Gnutella-র মতো নকশা কেন্দ্র সরিয়ে দিল — প্রশ্ন ছড়াত peer থেকে peer-এ (flooding), যা বড় নেটওয়ার্কে প্রচুর অপ্রয়োজনীয় ট্রাফিক তৈরি করত। পরে কিছু নকশা “supernode” নামে বেশি ক্ষমতার peer বেছে তাদের মধ্যে সূচি রাখল।
BitTorrent (২০০১) আলাদা প্রশ্নের উত্তর দিল: খোঁজা নয়, দ্রুত বিতরণ। ফাইলকে chunk-এ ভাগ, প্রতিটির hash, rarest-first আর tit-for-tat — অংশ ৩-এর self-scalability বাস্তবে আনার কৌশল। Peer খোঁজার জন্য প্রথমে tracker, পরে Kademlia-ভিত্তিক DHT, যাতে কোনো একক কেন্দ্র না থাকে।
তবু ইউটিউব বা নেটফ্লিক্সের মতো সেবা মূলত CDN ব্যবহার করে। কারণ কয়েকটি: (১) ব্যবহারকারীর আপলোড গতি কম আর মোবাইল ডেটা দামি — মানুষ নিজের ডেটা খরচ করে অন্যকে ভিডিও দিতে চান না; (২) ফোনের ব্যাটারি আর NAT-এর পেছনের যন্ত্রে P2P কঠিন; (৩) কোম্পানি গুণমান, নিরাপত্তা আর অধিকার নিয়ন্ত্রণ করতে চায়; (৪) ব্যান্ডউইথ আর সার্ভারের দাম অনেক কমেছে, আর ISP-র নেটওয়ার্কের ভেতরে cache বসানো যায়। P2P তবু বেঁচে আছে যেখানে তার সুবিধা স্পষ্ট: বড় ওপেন-সোর্স ফাইল বিতরণ, ভিডিও কলের সরাসরি পথ (WebRTC), আর কিছু সফটওয়্যারের আপডেট বিতরণে।
মূল উপলব্ধি: গঠন বাছাই শুধু গণিতের প্রশ্ন নয়। P2P তাত্ত্বিকভাবে সবচেয়ে ভালোভাবে বড় হয়, কিন্তু খরচ কে দেবে, নিয়ন্ত্রণ কার হাতে, আর ব্যবহারকারীর যন্ত্রের সীমা কী — এসব মিলিয়েই বাস্তবের সিদ্ধান্ত।
প্র ০৩HTTP/1.1, SMTP-এর মতো text protocol চার দশক টিকে আছে, অথচ HTTP/2, QUIC binary বেছে নিল। Text আর binary-র এই টানাপোড়েন, আর “যা পান তাতে উদার হোন” নীতির শিক্ষা কী?
Text protocol-এর সবচেয়ে বড় গুণ স্বচ্ছতা। আশি-নব্বইয়ের দশকে একজন প্রশাসক telnet দিয়ে মেইল সার্ভারের port 25-এ যুক্ত হয়ে নিজের হাতে HELO, MAIL FROM টাইপ করে সমস্যা খুঁজতে পারতেন। নতুন header যোগ করা সহজ, পুরোনো সফটওয়্যার অচেনা header উপেক্ষা করে। এই সহজলভ্যতাই SMTP আর HTTP-কে এত ব্যাপক করেছে।
কিন্তু text-এর লুকোনো খরচ আছে — অস্পষ্টতা। লাইন শেষ হবে CRLF-এ, নাকি শুধু LF-এ চলবে? header-এর নামে বড়-ছোট হাতের অক্ষর? দুটি space? দুটি Content-Length থাকলে কোনটি? শুরুর দিকে Jon Postel-এর সূত্র ছিল “যা পাঠান তাতে রক্ষণশীল হোন, যা পান তাতে উদার হোন” — একে বলে robustness principle. এতে শুরুর দিকে সফটওয়্যারগুলো একে অপরের সাথে সহজে চলেছে, কিন্তু দীর্ঘমেয়াদে উল্টো ফল দিয়েছে: প্রতিটি implementation ভিন্ন ভিন্ন ভুল মেনে নেয়, আর সেই পার্থক্যই নিরাপত্তার ফাঁক হয়ে দাঁড়ায় — যেমন HTTP request smuggling, যেখানে একটি proxy আর একটি সার্ভার একই বাইটকে ভিন্নভাবে ভাগ করে। IETF-এর RFC 9413 (২০২৩) এই অভিজ্ঞতা নিয়ে লিখেছে যে অতি-উদারতা protocol-কে সময়ের সাথে ক্ষয় করে, আর ভুল ইনপুটের ব্যাপারে কড়া হওয়াই ভালো।
HTTP/2 binary হলো মূলত দক্ষতার জন্য: নির্দিষ্ট মাপের frame-এ ভাগ করলে একটি সংযোগে অনেক অনুরোধ পাশাপাশি চালানো যায়, header সংকোচন (HPACK) করা যায়, আর parse করা দ্রুত ও নির্ভুল। QUIC আরও এগিয়ে header-ও এনক্রিপ্ট করে। হারানো স্বচ্ছতা ফিরিয়ে আনে টুল — Wireshark, ব্রাউজারের developer tools. আর মজার ব্যাপার, HTTP-র অর্থ (GET, status code, header-এর নাম) সব সংস্করণে একই রাখা হয়েছে (RFC 9110); বদলেছে শুধু তারে লেখার রূপ।
মূল উপলব্ধি: Text শেখা আর debug করার জন্য চমৎকার, binary দক্ষতা আর নির্ভুলতার জন্য। যেটিই বাছুন, spec-এ অস্পষ্টতা রাখবেন না আর ভুল ইনপুটে কড়া থাকুন — উদারতার দাম পরে নিরাপত্তা দিয়ে শোধ করতে হয়।
প্র ০৪HTTP-কে stateless রাখা কি ভুল সিদ্ধান্ত ছিল, যখন প্রায় সব ওয়েবসাইটই লগইন, কার্ট আর session মনে রাখে? Stateless আর stateful নকশার আসল বিনিময় কী?
প্রথম দিকের ওয়েব ছিল দলিল পড়ার ব্যবস্থা: একটি পাতা চাওয়া, পাওয়া, শেষ। সেখানে অবস্থা মনে রাখার দরকারই ছিল না, আর stateless নকশা সার্ভারকে অত্যন্ত সরল রেখেছিল। কিন্তু ব্যবসা আর কেনাকাটা আসতেই “এই ব্যবহারকারী কে” মনে রাখা দরকার হলো। ১৯৯৪ সালে Netscape-এ Lou Montulli cookie-র ধারণা আনেন — সার্ভার একটি ছোট লেবেল দেয়, ব্রাউজার প্রতিটি অনুরোধে তা ফেরত দেয়। পরে এটি IETF-এ মানসম্মত হয়, বর্তমানে RFC 6265-এ। লক্ষ করুন, protocol stateless-ই থাকল; অবস্থা গেল অ্যাপের স্তরে, ঐচ্ছিকভাবে।
এই বিভাজনের শক্তি বোঝা যায় বড় হলে। Stateless অনুরোধ যেকোনো সার্ভার সামলাতে পারে, তাই load balancer হাজার সার্ভারে অনুরোধ ছড়িয়ে দিতে পারে, একটি সার্ভার বসে গেলে অন্যটি কাজ নেয়, আর মাঝের cache নির্দ্বিধায় উত্তর জমিয়ে রাখতে পারে। Roy Fielding ২০০০ সালের তাঁর doctoral dissertation-এ REST নামে ওয়েবের যে গঠন-নীতি বর্ণনা করেন, তার একটি মূল শর্তই হলো এই statelessness. অবস্থা রাখতে হয় এমন জায়গায় যেখানে সবাই পায় — একটি ভাগ করা ডেটাবেস বা cache, বা স্বাক্ষর করা token-এর ভেতরেই।
Stateful নকশার সুবিধাও বাস্তব: প্রতিটি বার্তায় পুরো পরিচয় আর প্রসঙ্গ পাঠাতে হয় না, তাই বার্তা ছোট, আর দীর্ঘ কাজ (একটি mailbox খোলা রেখে অনেক চিঠি পড়া, একটি ডেটাবেস transaction) স্বাভাবিকভাবে চলে। খরচ: সংযোগ বা সার্ভার হারালে অবস্থা হারায়, আর সার্ভার ভাগ করা কঠিন — একই client-কে একই সার্ভারে পাঠাতে হয়, যাকে বলে “sticky session”. এজন্য বাস্তবে মিশ্রণই চলে: TCP সংযোগ stateful, তার ওপর HTTP stateless, তার ওপর অ্যাপের session আবার stateful.
মূল উপলব্ধি: HTTP-র statelessness ভুল নয়, বরং বড় হওয়ার চাবি; অবস্থা নিষিদ্ধ নয়, শুধু protocol থেকে সরিয়ে অ্যাপের হাতে, এমন জায়গায় রাখা যেখানে তা ভাগ করা আর পুনরুদ্ধার করা যায়।
প্র ০৫যেকোনো প্রতিষ্ঠানের মেইল সার্ভার একে অপরকে চিঠি পাঠাতে পারে, কিন্তু এক মেসেজিং অ্যাপ থেকে আরেক অ্যাপে মেসেজ যায় না। খোলা বনাম মালিকানাধীন protocol-এর এই পার্থক্য কীভাবে তৈরি হলো, আর তার মূল্য কী?
ইমেইল জন্মেছিল একটি গবেষণা নেটওয়ার্কে, যেখানে অনেক বিশ্ববিদ্যালয় আর প্রতিষ্ঠান নিজ নিজ কম্পিউটার চালাত। কেউ একা সবকিছুর মালিক ছিল না, তাই একমাত্র পথ ছিল একটি খোলা নিয়ম — SMTP, ১৯৮২ সালে RFC 821-এ, আজ RFC 5321-এ। IETF-এর কাজের ধারা এই সংস্কৃতিকে ধরে রেখেছে; David Clark-এর ১৯৯২ সালের একটি বিখ্যাত উক্তি প্রায় মন্ত্রের মতো: “We reject kings, presidents and voting. We believe in rough consensus and running code.” — মোটামুটি ঐকমত্য আর সত্যিই চলা কোড। ফল: আজও যেকোনো প্রতিষ্ঠান নিজের মেইল সার্ভার চালিয়ে বাকি পৃথিবীর সাথে চিঠি বিনিময় করতে পারে।
আধুনিক মেসেজিং অ্যাপগুলো জন্মেছে ভিন্ন পরিবেশে — একটি কোম্পানি, কেন্দ্রীয় সার্ভার, দ্রুত নতুন ফিচার আর ব্যবহারকারীর সংখ্যা দিয়ে প্রতিযোগিতা। নিজস্ব protocol থাকলে কোম্পানি এক রাতে নতুন ফিচার চালু করতে পারে, কাউকে জিজ্ঞেস না করে। End-to-end encryption-এর মতো জটিল জিনিসও নিজের মতো করে দ্রুত বসানো যায়। কিন্তু মূল্য দেন ব্যবহারকারী: বন্ধুদের সাথে কথা বলতে প্রত্যেক অ্যাপ আলাদা রাখতে হয়, আর একটি অ্যাপ ছাড়লে পুরোনো যোগাযোগও হারান — একে বলে “network effect”-এর তালা।
এই পার্থক্য কমানোর চেষ্টা আছে দুই দিক থেকে। প্রযুক্তিতে, IETF ২০২৩ সালে Messaging Layer Security (MLS, RFC 9420) প্রকাশ করেছে — বড় গ্রুপে end-to-end encryption-এর একটি খোলা মান। নীতিতে, ইউরোপীয় ইউনিয়নের Digital Markets Act বড় মেসেজিং সেবাগুলোকে অন্যদের সাথে আন্তঃকার্যক্ষমতার (interoperability) দিকে ঠেলছে — বাস্তবায়ন এখনো চলমান। খোলা protocol-এরও দুর্বলতা আছে: ধীর পরিবর্তন, আর পুরোনো সংস্করণের সাথে সামঞ্জস্য রাখার বোঝা — যেমন ইমেইলে প্রেরক-যাচাই (SPF, DKIM, DMARC — পর্ব ৩৯) পরে জুড়তে হয়েছে।
মূল উপলব্ধি: খোলা protocol উদ্ভাবন ধীর করে কিন্তু ব্যবহারকারীকে স্বাধীনতা দেয়; মালিকানাধীন protocol দ্রুত এগোয় কিন্তু ব্যবহারকারীকে আটকে রাখে। কোনটি টেকে, তা ঠিক হয় প্রযুক্তির চেয়েও বেশি অর্থনীতি আর নীতিতে।
অনুশীলন
খাতা-কলম নিন — প্রতিটি পদ আলাদা করে লিখে হিসাব করুন।
-
হিসাব (বিতরণের সময়): একটি ৫০০ MB ফাইল (F = ৪,০০০ Mbit) N = ২০ জনকে দিতে হবে। সার্ভারের আপলোড u_s = ৫০ Mbps, সবচেয়ে ধীর peer-এর ডাউনলোড d_min = ১০ Mbps, প্রতিটি peer-এর আপলোড u = ২ Mbps. (ক) D_cs আর D_P2P কত? (খ) N অনেক বড় হলে D_P2P কোন মানের দিকে যায়? (গ) কোন সবচেয়ে ছোট N থেকে D_cs-এর মান F/d_min-এর চেয়ে বড় হয়?
(ক) Client-server: NF/u_s = ২০ × ৪,০০০ / ৫০ = ১,৬০০ সেকেন্ড; F/d_min = ৪,০০০ / ১০ = ৪০০ সেকেন্ড। D_cs = ১,৬০০ সেকেন্ড ≈ ২৬.৭ মিনিট. P2P: F/u_s = ৮০; F/d_min = ৪০০; NF/(u_s + Nu) = ৮০,০০০ / (৫০ + ৪০) = ৮০,০০০ / ৯০ ≈ ৮৮৮.৯ সেকেন্ড। D_P2P ≈ ৮৮৮.৯ সেকেন্ড ≈ ১৪.৮ মিনিট.
(খ) NF/(u_s + Nu) → F/u = ৪,০০০ / ২ = ২,০০০ সেকেন্ড (প্রায় ৩৩.৩ মিনিট) — তার বেশি কখনো নয়। (গ) NF/u_s > F/d_min ⇔ N > u_s/d_min = ৫০/১০ = ৫, তাই N = ৬ থেকে (৬ × ৮০ = ৪৮০ > ৪০০)।
-
আউটপুট অনুমান করুন: অংশ ৭-এর KV/1 parser-এ শুধু
chunksবদলে করা হলো["set Roll 7\r\nGET ro", "ll\r\nGET Roll\r\nDEL Roll extra\r\n"]. পুরো আউটপুট কী হবে?-- chunk 1 arrives (18 bytes) C: set Roll 7 S: OK (waiting: "GET ro" has no CRLF yet) -- chunk 2 arrives (30 bytes) C: GET roll S: NOT_FOUND C: GET Roll S: VALUE 7 C: DEL Roll extra S: ERR wrong number of arguments final state: {"Roll":"7"}ছোট হাতের
setকাজ করে (command case-insensitive), কিন্তু key case-sensitive — তাইrollআরRollআলাদা, প্রথম GET পায় NOT_FOUND. প্রথম টুকরো ১০ + ২ + ৬ = ১৮ বাইট, দ্বিতীয়টি ৪ + ১০ + ১৬ = ৩০ বাইট। DEL-এ তিনটি শব্দ, তাই syntax ভুল আর key মোছা হয় না। -
শ্রেণিবিভাগ: নিচের protocol-গুলোকে তিন মাপকাঠিতে সাজান — text না binary; stateless না stateful (protocol-এর দিক থেকে); push না pull: (ক) SMTP দিয়ে এক মেইল সার্ভার থেকে আরেকটিতে চিঠি, (খ) IMAP দিয়ে mailbox পড়া, (গ) HTTP/1.1, (ঘ) DNS query, (ঙ) MQTT-তে সেন্সরের publish.
(ক) SMTP — text, stateful (MAIL FROM → RCPT TO → DATA ক্রম মানতে হয়), push. (খ) IMAP — text, stateful (লগইন আর SELECT করা mailbox মনে থাকে), pull. (গ) HTTP/1.1 — text, stateless, pull. (ঘ) DNS — binary, stateless, pull (প্রশ্ন করে উত্তর আনা)। (ঙ) MQTT — binary; সংযোগ আর subscription-এর অবস্থা থাকে বলে stateful; সেন্সর broker-এ push করে, আর broker subscriber-দের কাছে push করে।
-
কোড লিখুন: KV/1-এ একটি নতুন command যোগ করুন:
INCR key— key না থাকলে মান 1 রাখে, থাকলে সংখ্যাটি এক বাড়ায়, আর উত্তর দেয়VALUE n; মান সংখ্যা না হলেERR not a number. JS parser-এরhandle()-এ কী কী বদলাবেন? Spec-এ নতুন নিয়মটি RFC 2119-এর ভাষায় লিখুন।const ARITY = { SET: 3, GET: 2, DEL: 2, INCR: 2, QUIT: 1 }; // ... handle() এর ভেতরে, GET-এর পরে: if (cmd === "INCR") { const old = store.has(key) ? store.get(key) : "0"; if (!/^-?[0-9]+$/.test(old)) return "ERR not a number"; const n = String(Number(old) + 1); store.set(key, n); return "VALUE " + n; }Spec-এ যোগ: “INCR key: If the key does not exist, the server MUST treat its value as 0. If the stored value is not a decimal integer, the server MUST reply ERR and MUST NOT change the value. Otherwise the server MUST add 1, store the result and reply VALUE n.” ক্রমমতো
INCR visitsদুবার দিলে উত্তরVALUE 1, তারপরVALUE 2; আরSET city Dhaka-এর পরINCR cityদিলেERR not a number. বাস্তব সার্ভারে বড় সংখ্যার সীমা (overflow) নিয়েও একটি নিয়ম লিখতে হতো।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমব্রাউজারে https:// দিয়ে শুরু একটি URL লিখে Enter চাপার পর (HTTP/1.1 বা HTTP/2 ধরে) ঘটনাগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- ব্রাউজার URL ভেঙে scheme, host আর path আলাদা করে
- DNS দিয়ে host-এর নাম থেকে IP ঠিকানা পাওয়া
- সেই IP-র port 443-এ TCP three-way handshake
- TLS handshake — key ঠিক করা আর certificate যাচাই
- HTTP GET পাঠানো আর response পাওয়া
- HTML পড়ে বাকি CSS, ছবি আর script চেয়ে পাতা আঁকা
একটি সার্ভার (আপলোড ১০০ Mbps) ২০ জন client-কে ১,০০০ Mbit-এর একটি ফাইল দেবে; সবচেয়ে ধীর client-এর ডাউনলোড ৫০ Mbps. Client-server গঠনে সর্বনিম্ন বিতরণ-সময় কত?
- ২০ সেকেন্ড
- ১০ সেকেন্ড
- ২০০ সেকেন্ড
- ৪০০ সেকেন্ড
P2P ফাইল বিতরণে সব peer-এর আপলোড গতি u হলে peer-এর সংখ্যা N খুব বড় হতে থাকলে সর্বনিম্ন বিতরণ-সময়ের কী ঘটে?
- N-এর সাথে সরলরেখায় বাড়ে
- একটি সীমার (মোটামুটি F/u) দিকে স্থির হয়ে যায়
- শূন্যের দিকে কমে যায়
- N-এর বর্গের হারে বাড়ে
নিচের কোন application-layer protocol-এর বার্তা binary আকারে, অর্থাৎ নির্দিষ্ট বাইটে নির্দিষ্ট মাপের ঘর দিয়ে লেখা?
- HTTP/1.1
- SMTP
- POP3
- DNS
একটি RFC-তে লেখা: “A client SHOULD send QUIT before closing the connection.” RFC 2119 অনুযায়ী এর অর্থ কী?
- জোরালো সুপারিশ; উপযুক্ত কারণ থাকলে ব্যতিক্রম চলে
- বাধ্যতামূলক; না মানলে implementation অবৈধ
- সম্পূর্ণ ঐচ্ছিক, কোনো পছন্দ নেই
- QUIT পাঠানো নিষেধ
BitTorrent-এ একজন peer প্রথমে সেই chunk চায়, যা তার প্রতিবেশীদের মধ্যে সবচেয়ে কম কপিতে আছে। এই নিয়মের প্রধান উদ্দেশ্য কী?
- ফাইলটি শুরু থেকে ক্রমমতো পাওয়া, যাতে আগে খোলা যায়
- যে peer বেশি আপলোড করে তাকে পুরস্কৃত করা
- বিরল chunk হারিয়ে যাওয়া ঠেকানো আর সব chunk সমানভাবে ছড়িয়ে দেওয়া
- Tracker-এর ভার কমানো
একটি খামারের সেন্সর MQTT-তে “farm/pond1/oxygen” topic-এ প্রতি মিনিটে মান publish করে; তিনটি আলাদা অ্যাপ এই topic-এ subscribe করে আছে। কোন কথাটি সঠিক?
- সেন্সর তিনটি অ্যাপের IP জেনে প্রত্যেককে আলাদা করে পাঠায়
- সেন্সর একটি broker-কে পাঠায়, broker তিন subscriber-কে পৌঁছে দেয়
- প্রতিটি অ্যাপ প্রতি সেকেন্ডে সেন্সরকে জিজ্ঞেস করে নতুন মান আছে কি না
- MQTT একটি text protocol, যা UDP-র ওপর চলে
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Protocol = বার্তার ধরন + syntax + semantics + নিয়ম। খোলা protocol RFC-তে লেখা; MUST বাধ্যতামূলক, SHOULD জোরালো সুপারিশ, MAY ঐচ্ছিক। অ্যাপ চলে শুধু end system-এ — নতুন অ্যাপের জন্য নেটওয়ার্ক বদলাতে হয় না।
- Client-server: সবসময়-চালু সার্ভার, data center; P2P: self-scalability কিন্তু অস্থির peer আর NAT; hybrid: খোঁজা কেন্দ্রে, ভারী কাজ প্রান্তে।
- D_cs = max(NF/u_s, F/d_min) — N-এর সাথে সরলরেখায়; D_P2P = max(F/u_s, F/d_min, NF/(u_s+Σu_i)) — F/u-এর নিচে সীমাবদ্ধ।
- BitTorrent: chunk আর hash, tracker বা DHT, rarest-first (বিরল chunk আগে), tit-for-tat (যে দেয় তাকে দেওয়া) আর optimistic unchoke.
- Process-এর ঠিকানা = IP + port, দরজা socket. নকশার সিদ্ধান্ত: text বনাম binary, stateless বনাম stateful, push বনাম pull, request-response বনাম pub-sub বনাম streaming; TCP byte-স্রোত বলে framing protocol-এর দায়িত্ব।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৩৫ · DNS — নাম থেকে ঠিকানা, resolver আর cachingপরবর্তী পর্বএকটি ক্লিকের প্রথম ধাপের ভেতরের গল্প।
- পর্ব ৩৬ · HTTP — request, response, header, cookie আর RESTএই মডিউলওয়েবের text protocol আর stateless নকশা।
- পর্ব ২৭ · Transport layer — port, socket আর multiplexingভিত্তিSocket, port আর TCP বনাম UDP-র সিদ্ধান্ত।
- পর্ব ০২ · নেটওয়ার্কের ধরন আর topologyভিত্তিClient-server আর P2P-র প্রথম পরিচয়।
- কম্পিউটার নেটওয়ার্ক · কোর্স হোম৬২টি পর্বHTTP/2–3 (পর্ব ৩৭), CDN (পর্ব ৩৮), ইমেইল (পর্ব ৩৯), streaming (পর্ব ৪০) আর socket প্রোগ্রামিং (পর্ব ৪১–৪৫)।
- DSA · Hash tableপাশের ট্র্যাকDHT-র পেছনের মূল ডেটা স্ট্রাকচার।
- DBMS · Distributed databaseপাশের ট্র্যাকঅনেক যন্ত্রে ডেটা ভাগ — P2P আর data center-এর আরেক দিক।