সরাসরি পর্বে যান
পর্ব ২৭ · ৬২-এর মধ্যে · মডিউল ৫

Transport layer — port, socket আর multiplexing

The Transport Layer — Process-to-Process Delivery, Port Numbers, Sockets, Multiplexing & Demultiplexing, TCP vs UDP

Taught in Bangla, this lesson explains how the transport layer extends host-to-host IP delivery to process-to-process delivery using port numbers. It covers well-known, registered and dynamic port ranges, ephemeral ports, sockets and the 4-tuple, connectionless and connection-oriented demultiplexing, and what TCP and UDP do and do not guarantee, with hands-on examples.

এই পর্বে যা শিখবেন

  • Transport layer-এর আসল কাজ — host-to-host IP-র ওপর process-to-process যোগাযোগ — আর এটি কোথায় চলে, কোথায় চলে না
  • একটি অ্যাপ নেটওয়ার্কের কাছে কী কী চায়, আর TCP ও UDP তার কোনটা দেয়, কোনটা দেয় না
  • Port নম্বরের তিন ভাগ, পরিচিত port-এর তালিকা, আর Linux-এ ephemeral port-এর আসল পরিসর নিজের চোখে দেখা
  • UDP-র 2-tuple আর TCP-র 4-tuple দিয়ে demultiplexing — হাতে-কলমে উদাহরণ, simulator আর C প্রোগ্রামে
  • Socket, listening আর connected socket; flow control বনাম congestion control; ossification আর কোন অ্যাপে কোন transport

১ · Transport layer-এর কাজ — host থেকে process পর্যন্ত

আপনার ল্যাপটপে এই মুহূর্তে হয়তো ব্রাউজারের পাঁচটি ট্যাব খোলা, পাশে একটি মেসেজিং অ্যাপ, ব্যাকগ্রাউন্ডে সফটওয়্যার আপডেট, আর একটি গানের অ্যাপ। সবার ডেটা আসছে একই Wi-Fi দিয়ে, একই IP ঠিকানায়। Network layer (মডিউল ৩) packet-কে ঠিকঠাক আপনার ল্যাপটপ পর্যন্ত এনে দেয় — কিন্তু তারপর? ল্যাপটপের ভেতরে কোন প্রোগ্রাম এই packet পাবে, তা IP জানে না, জানার দায়ও তার নয়। এই শেষ ধাপটুকু, আর তার সাথে আরও কিছু প্রতিশ্রুতি, যে স্তরের কাজ, তার নাম transport layer.

দুটি পরিবার ভাবুন — একটি ঢাকার মিরপুরে, একটি চট্টগ্রামের আগ্রাবাদে। দুই বাড়িতেই পাঁচ-ছয়জন চাচাতো ভাইবোন, প্রত্যেকে প্রতি সপ্তাহে অন্য বাড়ির কাউকে চিঠি লেখে। দুই বাড়িতে একজন করে বড় ভাই আছেন: তিনি বাড়ির সবার চিঠি জড়ো করে ডাকঘরে দেন, আর ডাকপিয়ন যে চিঠির বান্ডিল দিয়ে যান, খামের ওপরের নাম দেখে তা ঠিক মানুষের হাতে পৌঁছে দেন। ডাক বিভাগ = network layer — সে শুধু বাড়ির ঠিকানা চেনে, বাড়ির ভেতরে কে কার চিঠি পাবে জানে না। বড় ভাই = transport layer — বাড়ির ভেতরে প্রত্যেক মানুষ পর্যন্ত পৌঁছে দেওয়া তাঁর কাজ। বাড়ির ঠিকানা = IP ঠিকানা, খামের ওপরের নাম = port নম্বর, ভাইবোনেরা = process (চলমান প্রোগ্রাম)। আর একটি জরুরি কথা: বড় ভাই শুধু বাড়ির ভেতরে কাজ করেন; পথের কোনো ডাকঘরে বসে তিনি চিঠি খোলেন না।

Logical যোগাযোগ — যেন দুই প্রোগ্রাম সরাসরি যুক্ত

Transport layer অ্যাপের জন্য একটি সুন্দর বিভ্রম তৈরি করে। ঢাকার একটি ব্রাউজার আর সিঙ্গাপুরের একটি ওয়েব সার্ভারের মাঝে হয়তো পনেরোটি router, কয়েকটি সমুদ্রের তলার কেবল আর তিনটি ISP. কিন্তু দুই প্রোগ্রামের কাছে মনে হয় যেন তারা একটি সরাসরি নালি দিয়ে যুক্ত — এক প্রান্তে লিখলে অন্য প্রান্তে পড়া যায়। এই “যেন সরাসরি” সংযোগকে বলে logical যোগাযোগ. পর্ব ০৩-এর ভাষায়, প্রতিটি স্তর তার peer-এর সাথে কথা বলে: ক্লায়েন্টের TCP সার্ভারের TCP-র সাথে, মাঝের router-দের কথা না ভেবে।

দুই স্তরের কাজের পার্থক্য তাই এক লাইনে: network layer = host-to-host, transport layer = process-to-process. IP একটি packet-কে 198.51.100.7 থেকে 192.0.2.10-এ নেয়; TCP বা UDP সেটিকে 198.51.100.7-এর ব্রাউজার থেকে 192.0.2.10-এর ওয়েব সার্ভার প্রোগ্রামে নেয়। (এই পর্বের “public” ঠিকানাগুলো RFC 5737-এর ডকুমেন্টেশন ব্লক থেকে নেওয়া — বাস্তবে কারও নয়।)

কোথায় চলে — শুধু প্রান্তে

Transport layer চলে শুধু end system-এ — আপনার ফোন, ল্যাপটপ, সার্ভার — সাধারণত OS-এর kernel-এর ভেতরে। পথের router নিয়ম মেনে চললে network layer পর্যন্ত দেখে: IP header পড়ে, গন্তব্য অনুযায়ী পরের hop-এ পাঠায়, TCP বা UDP অংশ ছোঁয় না (পর্ব ১৫)। এটাই পর্ব ০৩-এর end-to-end নীতি-র ফল — বুদ্ধি দুই প্রান্তে, নেটওয়ার্কের মাঝখান সরল।

বাস্তবে ব্যতিক্রম আছে। NAT router port নম্বর বদলায় (পর্ব ১৯), firewall port দেখে আটকায়, load balancer port দেখে সার্ভার বাছে — এগুলো middlebox. এমনকি সাধারণ router-ও অনেক সময় একাধিক সমান পথের মধ্যে ভাগ করতে (ECMP) port নম্বর পড়ে hash করে, যাতে একটি সংযোগের সব packet একই পথে যায়। কিন্তু তারা transport-এর কাজ (পুনরায় পাঠানো, ক্রম ঠিক রাখা) করে না। এই “মাঝের যন্ত্রগুলো port দেখে” তথ্যটি অংশ ৭-এ খুব জরুরি হবে।

নিচের stepper-এ একটি HTTP অনুরোধ ব্রাউজার থেকে বেরিয়ে স্তর ধরে নিচে নামে, পথের router পেরোয়, আর সার্ভারে স্তর ধরে ওপরে উঠে ঠিক প্রোগ্রামটিতে পৌঁছায়। প্রতিটি ধাপে কোন পরিচয় (ঠিকানা বা port) কাজে লাগল, খেয়াল করুন।

  1. ব্রাউজারapplicationmessage
  2. TCP (ক্লায়েন্ট)port যোগsegment
  3. IP (ক্লায়েন্ট)ঠিকানা যোগpacket
  4. Routerশুধু IP দেখেforward
  5. IP (সার্ভার)protocol = 6TCP-কে দেয়
  6. TCP (সার্ভার)4-tuple খোঁজাsocket বাছাই
  7. ওয়েব সার্ভারread(fd 7)message পেল
ডেটার রূপ আর যে পরিচয় কাজে লাগল
কোথায়
ডেটার রূপ
কাজে লাগা পরিচয়
  1. অ্যাপ শুধু লেখে। ব্রাউজার তার socket-এ (fd 5) একটি HTTP অনুরোধ লেখে। সে IP header বা port-এর হিসাব নিয়ে মাথা ঘামায় না — শুধু জানে কোন socket-এ লিখছে।
  2. Transport port বসায়। Kernel-এর TCP অংশ message-এর সামনে একটি TCP header জোড়ে: উৎস port 51000 (OS-এর বেছে দেওয়া ephemeral port), গন্তব্য port 80 (HTTP). এখন এটি একটি segment. এটাই multiplexing — অনেক প্রোগ্রামের ডেটা port-এর লেবেল লাগিয়ে একই IP-তে নামানো।
  3. Network ঠিকানা বসায়। IP অংশ segment-এর সামনে IP header জোড়ে: উৎস 198.51.100.7, গন্তব্য 192.0.2.10, আর protocol ঘরে 6 (মানে “ভেতরে TCP আছে”; UDP হলে 17). এখন এটি একটি packet. নিচের link স্তর একে frame-এ মুড়ে পাঠায় (পর্ব ০৩-এর encapsulation).
  4. Router শুধু IP পড়ে। পথের router গন্তব্য IP দেখে forwarding table থেকে পরের hop বাছে, TTL এক কমায় (64 থেকে 63), IP header-এর checksum নতুন করে হিসাব করে আর পাঠিয়ে দেয়। TCP header সে ব্যবহার করে না — port 80 না 443, তাতে তার কিছু যায় আসে না।
  5. সার্ভারের IP দেখে — “আমার জন্য?” গন্তব্য 192.0.2.10 নিজের ঠিকানা, তাই packet রাখা হয়। IP header সরিয়ে protocol ঘর দেখে: 6, তাই ভেতরের segment যায় TCP-র কাছে। এটা demultiplexing-এর প্রথম ধাপ — network স্তরে protocol নম্বর দিয়ে।
  6. TCP চারটি মান দিয়ে socket খোঁজে। (উৎস IP 198.51.100.7, উৎস port 51000, গন্তব্য IP 192.0.2.10, গন্তব্য port 80) — এই চারটি মিলিয়ে kernel একটি নির্দিষ্ট সংযোগের socket খুঁজে পায়, ধরা যাক fd 7. এটাই transport স্তরের demultiplexing, অংশ ৪-এর মূল বিষয়।
  7. প্রোগ্রাম শুধু পড়ে। ওয়েব সার্ভার প্রোগ্রাম read(7, …) করে হুবহু সেই message পায়, যা ব্রাউজার লিখেছিল। পথের পনেরোটি router বা তিনটি ISP-র কথা দুই প্রোগ্রামের কেউই জানল না — এটাই logical যোগাযোগ।
মূল ধারণা

Demultiplexing দুই ধাপে ঘটে: IP header-এর protocol ঘর ঠিক করে কোন transport (TCP 6, UDP 17, ICMP 1) packet পাবে, আর transport header-এর port (TCP-তে সাথে IP ঠিকানাও) ঠিক করে কোন socket পাবে। আর এই সবকিছু ঘটে প্রাপকের নিজের যন্ত্রে, পথে নয়।

২ · অ্যাপ কী চায়, আর TCP-UDP আসলে কী দেয়

Transport layer তার নিচের network layer-এর ওপর দাঁড়িয়ে আছে, আর ইন্টারনেটের IP দেয় শুধু best effort সেবা (পর্ব ১৫): packet হারাতে পারে, ক্রম উল্টে যেতে পারে, দুবার আসতে পারে, দেরি হতে পারে, বিট বদলে যেতে পারে। এর ওপরে transport কী গড়তে পারে, আর কী পারে না? আগে দেখি একটি অ্যাপ সাধারণত কী কী চায়:

নির্ভরযোগ্যতা আর ক্রম

পাঠানো প্রতিটি বাইট পৌঁছাবে, একবারই, ঠিক ক্রমে। ফাইল ডাউনলোড, ইমেইল, ব্যাংকের লেনদেন — একটি বাইট হারালেও চলবে না।

reliability · ordering

Throughput

কমপক্ষে একটি গতির নিশ্চয়তা — যেমন HD ভিডিওর জন্য কয়েক Mbps. কিছু অ্যাপ (ফাইল কপি) যা পাওয়া যায় তাতেই খুশি — এদের বলে elastic.

bandwidth

সময় (timing)

Delay একটি সীমার নিচে — ফোন কলে কথা আর কানে শোনার মাঝে বেশি দেরি হলে কথোপকথন অসহ্য হয়ে যায়; অনলাইন গেমেও তাই।

latency · jitter

নিরাপত্তা

পথে কেউ পড়তে বা বদলাতে পারবে না, আর অপর প্রান্ত সত্যিই সেই সার্ভার কি না যাচাই — encryption, integrity, authentication.

security

এবার দুই প্রধান transport protocol কী দেয় — আর, পরীক্ষায় যেটা বেশি জিজ্ঞেস হয়, কী দেয় না:

সেবাTCP (RFC 9293)UDP (RFC 768)
Process-to-process পৌঁছানো (port)হ্যাঁহ্যাঁ
Error detection (checksum)হ্যাঁহ্যাঁ (IPv4-এ ঐচ্ছিক, IPv6-এ বাধ্যতামূলক)
সংযোগ স্থাপনহ্যাঁ — connection-oriented, আগে handshake (পর্ব ২৯)না — connectionless, সরাসরি পাঠানো
নির্ভরযোগ্য, ক্রমমতো, একবারইহ্যাঁ — byte-স্রোত হিসেবে (পর্ব ৩০)না — হারাতে, উল্টাতে, দুবার আসতে পারে
বার্তার সীমানা রক্ষানা — দুবার লেখা একবারে পড়া যেতে পারেহ্যাঁ — একটি datagram মানে একটি বার্তা
Flow controlহ্যাঁ (পর্ব ৩১)না
Congestion controlহ্যাঁ (পর্ব ৩২)না — অ্যাপকেই ভদ্র থাকতে হয়
ন্যূনতম throughput বা সর্বোচ্চ delayনানা
Encryption আর authenticationনা — ওপরে TLS লাগে (পর্ব ৪৮)না — DTLS বা QUIC লাগে (পর্ব ৩৩)
Header-এর আকারকমপক্ষে ২০ বাইটঠিক ৮ বাইট

সময় আর throughput-এর নিশ্চয়তা কেন কেউ দিতে পারে না? কারণ transport চলে শুধু প্রান্তে, আর মাঝের router-এর queue (পর্ব ০৫) তার নিয়ন্ত্রণের বাইরে। ঢাকার কোনো রিকশাচালক যতই দক্ষ হোন, ফার্মগেটের জ্যাম পার হতে কত মিনিট লাগবে, তার প্রতিশ্রুতি দিতে পারেন না — রাস্তা তাঁর নয়। TCP পারে হারানো জিনিস আবার পাঠাতে, ক্রম মেলাতে, গতি কমিয়ে জ্যাম না বাড়াতে; কিন্তু নিচের নেটওয়ার্ক যা দেয় না, প্রান্তে বসে তা বানানো যায় না। নেটওয়ার্কের ভেতরে অগ্রাধিকার (QoS, পর্ব ২৬) দিয়ে কিছুটা সাহায্য সম্ভব, কিন্তু খোলা ইন্টারনেটে তা সাধারণত পাওয়া যায় না।

নামের কথা: segment, datagram, message

প্রতিটি স্তরের ডেটা-এককের (PDU) নাম আলাদা, আর পরীক্ষায় নামগুলো ঠিক লিখতে হয়: application স্তরে message, TCP-তে segment, UDP-তে datagram (RFC 768-এর নামই “User Datagram Protocol”), network স্তরে packet (IP datagram-ও বলা হয়), link স্তরে frame. অনেক বই (যেমন Kurose-Ross) দুই transport-এর এককই “segment” বলে — সেটাও ভুল নয়; শুধু এক লেখায় একই নিয়ম মেনে চলুন।

Connection-oriented বনাম connectionless

TCP কথা শুরুর আগে দুই প্রান্তে একটু “অবস্থা” (state) বানায়: sequence নম্বর কত থেকে শুরু, buffer কত বড় — এজন্য তিনটি ছোট segment বিনিময় হয় (three-way handshake, পর্ব ২৯)। মাঝের router এই সংযোগের কথা জানে না; সংযোগটা থাকে শুধু দুই প্রান্তের kernel-এ। তাই TCP-র সংযোগ একটি logical সংযোগ — পুরোনো টেলিফোনের circuit-এর মতো পথে সংরক্ষিত কিছু নয় (পর্ব ০৪)। UDP এসবের ধার ধারে না: socket খুলে সরাসরি datagram পাঠিয়ে দেওয়া যায়, যেন খামে ঠিকানা লিখে ডাকবাক্সে ফেলা। অন্যদিকে TCP যেন ফোন কল — আগে রিং, “হ্যালো”, তারপর কথা, শেষে “রাখছি”.

৩ · Port নম্বর — ১৬ bit-এর ঠিকানা, তিন ভাগ

TCP আর UDP দুই header-এরই প্রথম চার বাইটে দুটি ঘর: উৎস port আর গন্তব্য port, প্রতিটি ১৬ bit. তাই port নম্বর হতে পারে ০ থেকে ৬৫,৫৩৫ (২১৬ = ৬৫,৫৩৬টি মান)। খেয়াল রাখুন, TCP-র port 53 আর UDP-র port 53 দুটি সম্পূর্ণ আলাদা জিনিস — প্রতিটি protocol-এর নিজস্ব port-জগৎ।

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
┌───────────────────────────────┬───────────────────────────────┐
│       Source Port (16)        │     Destination Port (16)     │  ← TCP আর UDP দুটিতেই
├───────────────────────────────┴───────────────────────────────┤     প্রথম ৪ বাইট একই
│  UDP: Length (16), Checksum (16)   │   TCP: Sequence Number…  │
└───────────────────────────────────────────────────────────────┘

সার্ভার সাধারণত একটি পরিচিত, স্থির port-এ অপেক্ষা করে — যাতে client আগে থেকেই জানে কোথায় যোগাযোগ করতে হবে, যেমন সবাই জানে জরুরি ফোন নম্বর ৯৯৯. আর client-এর port সাধারণত অস্থায়ী: সংযোগ খোলার সময় OS একটি খালি নম্বর বেছে দেয়, সংযোগ শেষে নম্বরটি ফেরত যায়। একে বলে ephemeral port (পর্ব ১৯-এ NAT-এর আলোচনায় একবার দেখেছেন)। IANA port-এর পরিসরকে তিন ভাগে ভাগ করে রেখেছে (RFC 6335, ২০১১):

পরিসরIANA-র নামমোটকাজ
0–1023Well-known (System ports)১,০২৪প্রচলিত সেবা — SSH, DNS, HTTP, HTTPS. Unix-ধর্মী OS-এ সাধারণত এগুলোতে bind করতে বিশেষ অধিকার লাগে (Linux-এ root বা CAP_NET_BIND_SERVICE).
1024–49151Registered (User ports)৪৮,১২৮প্রতিষ্ঠান বা সফটওয়্যারের জন্য IANA-তে নিবন্ধিত — MySQL 3306, RDP 3389, PostgreSQL 5432.
49152–65535Dynamic / Private১৬,৩৮৪কখনো কাউকে বরাদ্দ হয় না; ephemeral port-এর জন্য IANA-র সুপারিশ করা পরিসর।

কিন্তু সব OS IANA-র সুপারিশ মানে না। Windows (Vista থেকে) আর macOS সাধারণত 49152–65535 থেকে ephemeral port দেয়, কিন্তু Linux-এর ডিফল্ট পরিসর আলাদা — আধুনিক kernel-এ সাধারণত 32768–60999, যা /proc/sys/net/ipv4/ip_local_port_range ফাইলে লেখা থাকে আর প্রশাসক বদলাতে পারেন। মানে Linux client-এর port 40000-ও হতে পারে, যা IANA-র হিসাবে “registered” ভাগে পড়ে! তাই port দেখে “এটা client, না সার্ভার” বলার সময় নিয়মটা হলো প্রবণতা, আইন নয়।

যে port-গুলো মুখস্থ রাখার মতো

PortTransportসেবাকোন পর্বে
20, 21TCPFTP (ডেটা, নিয়ন্ত্রণ)পর্ব ১৯-এ ALG প্রসঙ্গে
22TCPSSH — নিরাপদ remote loginপর্ব ৪৭–৪৮
23TCPTelnet — পুরোনো, এনক্রিপশনহীন; এড়িয়ে চলুন—
25, 587, 465TCPSMTP (সার্ভার-থেকে-সার্ভার, ইমেইল জমা, TLS-এ জমা)পর্ব ৩৯
53UDP আর TCPDNS — সাধারণত UDP, বড় উত্তর বা zone transfer-এ TCPপর্ব ৩৫
67, 68UDPDHCP (সার্ভার, client)পর্ব ১৮
80TCPHTTPপর্ব ৩৬
110, 143, 993TCPPOP3, IMAP, IMAPSপর্ব ৩৯
123UDPNTP — ঘড়ি মেলানো—
161UDPSNMP — নেটওয়ার্ক যন্ত্র পর্যবেক্ষণ—
443TCP, আর UDPHTTPS (TCP-র ওপর TLS); HTTP/3 চলে UDP 443-এ QUIC দিয়েপর্ব ৩৩, ৩৭, ৪৮
3306, 5432TCPMySQL, PostgreSQL—
3389TCP (আর UDP)RDP — Windows remote desktop—

একটি সতর্কতা: port নম্বর একটি প্রথা, প্রমাণ নয়। যে-কেউ port 443-এ অন্য কিছু চালাতে পারেন, বা SSH চালাতে পারেন 2222-এ। Firewall “port 80 মানেই ওয়েব” ধরে নিলে ভুল করবে — এটাই পরে আধুনিক firewall-কে packet-এর ভেতরও দেখতে বাধ্য করেছে (পর্ব ৪৯)।

নিজে চালিয়ে দেখুন: একটি port classifier

নিচের ছোট প্রোগ্রাম একগুচ্ছ port নম্বর নিয়ে বলে দেয় সেটি IANA-র কোন ভাগে, Linux-এর ডিফল্ট ephemeral পরিসরে পড়ে কি না, আর পরিচিত কোনো সেবার কি না। সীমানার মানগুলো (1023/1024, 49151/49152, 60999/61000) ইচ্ছা করেই রাখা — পরীক্ষায় ফাঁদ এখানেই।

// Port classifier: IANA range (RFC 6335) + Linux default ephemeral range + a few known services.
const KNOWN = { 20: "ftp-data", 21: "ftp", 22: "ssh", 23: "telnet", 25: "smtp", 53: "dns",
  67: "dhcp-server", 80: "http", 110: "pop3", 123: "ntp", 143: "imap", 443: "https",
  3306: "mysql", 3389: "rdp", 5432: "postgresql", 8080: "http-alt" };
const LINUX_EPH = [32768, 60999];            // default net.ipv4.ip_local_port_range
function classify(p) {
  if (!Number.isInteger(p) || p < 0 || p > 65535) return "invalid (port is 16 bits: 0-65535)";
  const range = p <= 1023 ? "well-known (system)" : p <= 49151 ? "registered (user)" : "dynamic/private";
  const eph = p >= LINUX_EPH[0] && p <= LINUX_EPH[1] ? "yes" : "no";
  return range.padEnd(21) + eph.padEnd(18) + (KNOWN[p] || "-");
}
const list = [22, 53, 123, 443, 1023, 1024, 3306, 8080, 32767, 32768, 49151, 49152, 60999, 61000, 65535, 65536];
console.log("port".padEnd(7) + "IANA range".padEnd(21) + "Linux ephemeral?".padEnd(18) + "service");
for (const p of list) console.log(String(p).padEnd(7) + classify(p));
const bits = Math.log2(65536);
console.log(`\n${bits} bits -> ${2 ** bits} port numbers per protocol per IP address`);
console.log(`well-known ${1024}, registered ${49151 - 1024 + 1}, dynamic ${65535 - 49152 + 1}, Linux ephemeral ${LINUX_EPH[1] - LINUX_EPH[0] + 1}`);

আউটপুট:

port   IANA range           Linux ephemeral?  service
22     well-known (system)  no                ssh
53     well-known (system)  no                dns
123    well-known (system)  no                ntp
443    well-known (system)  no                https
1023   well-known (system)  no                -
1024   registered (user)    no                -
3306   registered (user)    no                mysql
8080   registered (user)    no                http-alt
32767  registered (user)    no                -
32768  registered (user)    yes               -
49151  registered (user)    yes               -
49152  dynamic/private      yes               -
60999  dynamic/private      yes               -
61000  dynamic/private      no                -
65535  dynamic/private      no                -
65536  invalid (port is 16 bits: 0-65535)

16 bits -> 65536 port numbers per protocol per IP address
well-known 1024, registered 48128, dynamic 16384, Linux ephemeral 28232

তিনটি জিনিস লক্ষ করুন। প্রথমত, 32768 থেকে 49151 পর্যন্ত port একসাথে “registered” আর “Linux ephemeral” — দুই নিয়ম পরস্পরের ওপর পড়েছে। এজন্য Linux-এ কোনো সার্ভার যদি ধরুন port 40000-এ শুনতে চায়, আর ঠিক তখন কোনো client সংযোগ সেই port নিয়ে বসে থাকে, তবে সার্ভার চালু হতে পারে না; প্রশাসক তখন ip_local_reserved_ports দিয়ে port সংরক্ষণ করেন। দ্বিতীয়ত, 65536 অবৈধ — ১৬ bit-এ সবচেয়ে বড় সংখ্যা 65535. তৃতীয়ত, শেষ লাইনের হিসাব: মোট ১,০২৪ + ৪৮,১২৮ + ১৬,৩৮৪ = ৬৫,৫৩৬, আর Linux-এর ডিফল্টে ephemeral port ২৮,২৩২টি — এই সংখ্যাটি অংশ ৪-এর একটি হিসাবে আবার লাগবে।

এই container-এ আসল সংখ্যা আর শোনা socket দেখা

এবার একটি আসল Linux-এ দেখা যাক। নিচের স্ক্রিপ্ট kernel-এর ফাইল থেকে ephemeral পরিসর পড়ে, তারপর (perl থাকলে) loopback-এ একটি ছোট TCP listener (port 8080) আর একটি UDP socket (port 5300) খোলে, ss দিয়ে শোনা socket-গুলো দেখায়, শেষে bash-এর নিজস্ব /dev/tcp দিয়ে listener-এ সংযোগ করে সংযোগটির দুই প্রান্ত দেখায়। কোনো টুল না থাকলে স্ক্রিপ্ট তা জানিয়ে দেয়।

echo "== 1. ephemeral port range (Linux) =="
read -r lo hi < /proc/sys/net/ipv4/ip_local_port_range
echo "  ip_local_port_range = $lo..$hi  ($((hi - lo + 1)) ports)"
echo "== 2. a tiny TCP listener on 127.0.0.1:8080 and a UDP socket on :5300 =="
if command -v perl >/dev/null; then
  perl -MIO::Socket::INET -e '
    my $t = IO::Socket::INET->new(LocalAddr=>"127.0.0.1:8080", Listen=>5, ReuseAddr=>1) or die;
    my $u = IO::Socket::INET->new(LocalAddr=>"127.0.0.1:5300", Proto=>"udp") or die;
    my $c = $t->accept; sleep 3;' &
  srv=$!; sleep 1
else echo "  perl নেই — listener চালানো গেল না"; fi
echo "== 3. listening sockets: ss -tuln =="
if command -v ss >/dev/null; then ss -tuln
else echo "  ss নেই; /proc/net/tcp-এর LISTEN সারি (st=0A):"; awk '$4 == "0A"' /proc/net/tcp; fi
echo "== 4. connect from bash (/dev/tcp) and look at the connection =="
if exec 3<>/dev/tcp/127.0.0.1/8080 2>/dev/null; then
  sleep 0.5
  command -v ss >/dev/null && ss -tn state established '( sport = :8080 or dport = :8080 )'
  exec 3>&-
else echo "  সংযোগ হলো না (listener নেই)"; fi
[ -n "$srv" ] && wait "$srv" 2>/dev/null
echo "done"

আসল রানের আউটপুট:

== 1. ephemeral port range (Linux) ==
  ip_local_port_range = 32768..60999  (28232 ports)
== 2. a tiny TCP listener on 127.0.0.1:8080 and a UDP socket on :5300 ==
== 3. listening sockets: ss -tuln ==
Netid State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
udp   UNCONN 0      0          127.0.0.1:5300      0.0.0.0:*
tcp   LISTEN 0      5          127.0.0.1:8080      0.0.0.0:*
== 4. connect from bash (/dev/tcp) and look at the connection ==
Recv-Q Send-Q Local Address:Port  Peer Address:Port Process
0      0          127.0.0.1:56396    127.0.0.1:8080
0      0          127.0.0.1:8080     127.0.0.1:56396
done

১ — এই container-এর kernel ডিফল্ট মানেই আছে: 32768 থেকে 60999, মোট ২৮,২৩২টি port. (নিজের Linux-এ cat /proc/sys/net/ipv4/ip_local_port_range চালিয়ে মিলিয়ে নিন; distro বা প্রশাসক বদলে থাকলে আলাদা দেখাবে।) ৩ — ss -tuln মানে TCP (t) আর UDP (u), শুধু শোনা socket (l), নাম নয় সংখ্যা (n). দুটি সারি: TCP-র অবস্থা LISTEN, আর UDP-র UNCONN — UDP-তে “সংযোগ” বলে কিছু নেই, তাই সে শুধু খোলা। Peer ঘরে 0.0.0.0:* মানে “যে-কেউ”: এই socket-গুলো এখনো কোনো নির্দিষ্ট অপর প্রান্তের সাথে বাঁধা নয়। TCP-র Send-Q ঘরে 5 হলো listener-এর backlog (কতগুলো সংযোগ accept()-এর অপেক্ষায় জমতে পারে)।

৪ — সবচেয়ে মজার অংশ। bash সংযোগ খুলতেই kernel তাকে ephemeral port 56396 দিল — ঠিক 32768–60999-এর মধ্যে। (এই নম্বর প্রতিটি রানে বদলায় — আরেকটি রানে এসেছিল 36316, আর নিচের সারি দুটির ক্রমও উল্টে গিয়েছিল।) আর একটি সংযোগ দেখা যাচ্ছে দুটি সারিতে: একটি client-এর socket (local :56396, peer :8080), অন্যটি সার্ভারের দিকের socket (local :8080, peer :56396). দুটি আসলে একই চারটি মান, শুধু দুই দিক থেকে দেখা। Listener সারিটি এখানে নেই, কারণ আমরা শুধু established চেয়েছি — সে আলাদা socket হিসেবে আছে (অংশ ৫)। এখানে কোনো আসল host ঠিকানা আসেনি, সবই loopback (127.0.0.1).

৪ · Multiplexing আর demultiplexing — কোন segment কোন socket-এ

প্রেরকের দিকে অনেক socket-এর ডেটা জড়ো করে, প্রত্যেকটিতে port-এর header লাগিয়ে network layer-এ নামানো হলো multiplexing. প্রাপকের দিকে আসা segment-এর header দেখে ঠিক socket-এ পৌঁছে দেওয়া হলো demultiplexing. (পর্ব ০৮-এর FDM বা TDM-এর multiplexing-এর সাথে গুলিয়ে ফেলবেন না — সেখানে একটি তার বা তরঙ্গ ভাগ করা হয়, এখানে একটি IP ঠিকানা ভাগ করা হয় অনেক প্রোগ্রামের মধ্যে।) প্রশ্ন হলো: প্রাপক socket চেনে কোন কোন মান দিয়ে? উত্তর UDP আর TCP-তে আলাদা — আর এই পার্থক্য transport layer-এর সবচেয়ে বেশি জিজ্ঞাসিত প্রশ্নগুলোর একটি।

UDP: শুধু গন্তব্য — (গন্তব্য IP, গন্তব্য port)

একটি UDP socket bind করা থাকে একটি স্থানীয় ঠিকানা আর port-এ, যেমন 192.0.2.10:53. কোনো datagram এলে kernel দেখে শুধু তার গন্তব্য IP আর গন্তব্য port, আর সেই socket-এ দিয়ে দেয়। উৎস কে, তাতে কিছু আসে যায় না। ফলে ঢাকা থেকে একজন আর রাজশাহী থেকে আরেকজন একই DNS সার্ভারে প্রশ্ন পাঠালে দুটি datagram-ই একই socket-এ জমা হয়। তাহলে সার্ভার উত্তর কাকে পাঠাবে? প্রতিটি datagram পড়ার সময় recvfrom() উৎস IP আর port-ও জানিয়ে দেয়, আর সার্ভার sendto() দিয়ে ঠিক সেই ঠিকানায় উত্তর পাঠায়। উৎস port তাই UDP-তে “ফেরত ঠিকানা”র কাজ করে — চিঠির খামের পেছনে প্রেরকের ঠিকানার মতো।

TCP: পুরো চার মান — 4-tuple

একটি TCP সংযোগের socket চেনা যায় চারটি মানে: (উৎস IP, উৎস port, গন্তব্য IP, গন্তব্য port). প্রাপক kernel আসা segment-এর এই চারটি মান মিলিয়ে সংযোগটি খোঁজে। চারটির যেকোনো একটি আলাদা হলেই আলাদা সংযোগ, আলাদা socket. তাই একটি ওয়েব সার্ভারের port 80-এ একই সময়ে হাজার হাজার সংযোগ থাকতে পারে — সবার গন্তব্য 192.0.2.10:80, কিন্তু উৎস (IP, port) জোড়া প্রত্যেকের আলাদা। (পর্ব ১৯-এর 5-tuple = এই চারটি + protocol; একটি host-এর ভেতরে TCP আর UDP-র টেবিল আলাদা বলে TCP-র ভেতরে চারটিই যথেষ্ট।)

ক্লাসিক উদাহরণটি ধাপে ধাপে দেখুন: একটি ওয়েব সার্ভার 192.0.2.10:80, আর দুটি client — A (198.51.100.7, ব্রাউজারের দুটি ট্যাব) আর B (203.0.113.9). ইচ্ছা করেই B-র OS এমন একটি port বেছেছে, যা A-ও ব্যবহার করছে।

  1. সার্ভার192.0.2.10:80fd 3 LISTEN
  2. A · ট্যাব ১198.51.100.7port 40001
  3. A · ট্যাব ২198.51.100.7port 40002
  4. B203.0.113.9port 40001
  5. Lookup4-tupleঠিক socket
সার্ভারের socket table আর আসা segment
আসা segment
ফল
Socket table
  1. সার্ভার অপেক্ষায়। ওয়েব সার্ভার প্রোগ্রাম port 80-এ একটি listening socket (fd 3) খুলে রেখেছে। এর কোনো অপর প্রান্ত নেই — এটি শুধু নতুন সংযোগের অনুরোধ নেয়।
  2. A-র প্রথম ট্যাব। A-র OS ephemeral port 40001 বেছে SYN পাঠাল। সার্ভারে এই চার মানের কোনো সংযোগ নেই, তাই segment-টি listener-এর কাছে যায়; handshake শেষে accept() একটি নতুন socket দেয় — fd 4, যার চার মান (192.0.2.10, 80, 198.51.100.7, 40001).
  3. A-র দ্বিতীয় ট্যাব। একই কম্পিউটার, একই সার্ভার, কিন্তু OS নতুন port 40002 দিল। উৎস port আলাদা, তাই চার মান আলাদা → নতুন socket fd 5. একই IP থেকে দুটি সংযোগ শান্তিতে পাশাপাশি।
  4. B — একই port 40001! B-র OS-ও কাকতালীয়ভাবে 40001 বেছেছে। কোনো সমস্যা নেই: উৎস IP আলাদা (203.0.113.9), তাই চার মান আলাদা → fd 6. লক্ষ করুন, fd 4, 5, 6 — তিনটিরই local দিক 192.0.2.10:80.
  5. B-র ডেটা আসে। Segment-এর উৎস 203.0.113.9:40001. শুধু উৎস port দেখলে fd 4 আর fd 6 দুটোই মিলত — ভুল হতো। কিন্তু kernel চারটি মানই মেলায়: fd 4-এর উৎস IP 198.51.100.7, মেলে না; fd 6 মেলে। ডেটা যায় fd 6-এ।
  6. A-র দ্বিতীয় ট্যাবের ডেটা। উৎস 198.51.100.7:40002. fd 4-এর IP মেলে, কিন্তু port 40001 ≠ 40002; fd 5 পুরোপুরি মেলে। সারকথা: একটি সার্ভার port-এ অনেক socket, আর চার মানের অন্তত একটির পার্থক্যই তাদের আলাদা রাখে।

এবার একই দুই প্রেরক যদি UDP দিয়ে পাঠায়, কী বদলায়? নিচের stepper দুটি নিয়ম পাশাপাশি রাখে — বাম দিকে UDP-র DNS সার্ভার (port 53), ডান দিকে TCP-র ওয়েব সার্ভার (port 80), দুই প্রেরক X (198.51.100.7) আর Y (203.0.113.9).

একই ঘটনা, দুই transport
ঘটনা
UDP (সার্ভার :53)
TCP (সার্ভার :80)
  1. X পাঠাল। UDP-তে X-এর datagram (উৎস port 3333) গন্তব্য (192.0.2.10, 53) দেখে socket S1-এ গেল। TCP-তে X-এর segment (উৎস port 40001) চার মান দিয়ে খুঁজে সংযোগ-socket S3-এ গেল।
  2. Y পাঠাল। UDP-তে Y-এর datagram-এর গন্তব্যও (192.0.2.10, 53) — চাবি হুবহু এক, তাই আবার S1. TCP-তে Y-এর উৎস port-ও 40001, কিন্তু উৎস IP আলাদা, তাই চাবি আলাদা → S5. একই দুই প্রেরক: UDP-তে এক socket, TCP-তে দুই socket.
  3. উত্তর কীভাবে যায়। UDP সার্ভার একটি socket থেকেই সবাইকে উত্তর দেয়, তাই প্রতিটি recvfrom()-এ উৎস ঠিকানা জেনে প্রতিটি sendto()-এ তা বলে দিতে হয়। TCP সার্ভার শুধু write() করে — connected socket নিজেই জানে অপর প্রান্ত কে।
  4. কারও জন্য socket নেই। UDP port 9999-এ কেউ শুনছে না, তাই kernel datagram ফেলে দেয় আর সাধারণত একটি ICMP port unreachable (type 3, code 3) ফেরত পাঠায় (পর্ব ২০)। TCP port 22-এ কোনো listener নেই, তাই kernel একটি RST segment পাঠায় — “এখানে কেউ নেই”. Firewall থাকলে দুটিই প্রায়ই নীরবে ফেলে দেওয়া হয়।
  5. সারকথা। UDP socket চেনা হয় দুই মানে (গন্তব্য IP, গন্তব্য port), TCP সংযোগ চার মানে। TCP-র listening socket-এর আবার অপর প্রান্ত নেই, তাই কোনো সংযোগের সাথে না মিললে শুধু গন্তব্য দিয়ে তাকে খোঁজা হয় — নতুন সংযোগের অনুরোধ (SYN) সেখানেই যায়।

নিজে চালিয়ে দেখুন: একটি demultiplexing simulator

নিচের simulator একটি host (192.0.2.10)-এর socket-তালিকা রাখে — একটি UDP DNS socket, একটি TCP listener আর তিনটি চালু TCP সংযোগ (ঠিক উপরের stepper-এর মতো) — তারপর নয়টি আসা segment-কে kernel-এর নিয়মে ঠিক socket-এ পাঠায়: UDP শুধু গন্তব্য দিয়ে; TCP আগে পুরো চার মান দিয়ে, না মিললে SYN হলে listener-এ, নাহলে RST.

// Demultiplexing on host 192.0.2.10: which socket gets each arriving segment?
const H = "192.0.2.10";
const sockets = [   // UDP: bound (ip, port).  TCP: a listener, or a connection with a full 4-tuple
  { id: "S1 udp dns",    proto: "udp", lip: "*", lport: 53 },
  { id: "S2 tcp listen", proto: "tcp", lip: "*", lport: 80, listen: true },
  { id: "S3 tcp conn",   proto: "tcp", lip: H, lport: 80, rip: "198.51.100.7", rport: 40001 },
  { id: "S4 tcp conn",   proto: "tcp", lip: H, lport: 80, rip: "198.51.100.7", rport: 40002 },
  { id: "S5 tcp conn",   proto: "tcp", lip: H, lport: 80, rip: "203.0.113.9",  rport: 40001 },
];
const ipOk = (s, dip) => s.lip === "*" || s.lip === dip;
function demux(p) {
  if (p.proto === "udp") {             // UDP: only (dst IP, dst port) matter
    const s = sockets.find(s => s.proto === "udp" && s.lport === p.dport && ipOk(s, p.dip));
    return s ? s.id : "none -> ICMP port unreachable";
  }
  const c = sockets.find(s => s.proto === "tcp" && !s.listen && s.lip === p.dip &&
    s.lport === p.dport && s.rip === p.sip && s.rport === p.sport);   // TCP: full 4-tuple first
  if (c) return c.id;
  const l = sockets.find(s => s.listen && s.lport === p.dport && ipOk(s, p.dip));
  if (l && p.syn) return l.id + " (new connection request)";
  return "none -> TCP RST";
}
const arrivals = [
  { proto: "udp", sip: "198.51.100.7", sport: 3333,  dip: H, dport: 53 },
  { proto: "udp", sip: "203.0.113.9",  sport: 4444,  dip: H, dport: 53 },
  { proto: "tcp", sip: "198.51.100.7", sport: 40001, dip: H, dport: 80 },
  { proto: "tcp", sip: "198.51.100.7", sport: 40002, dip: H, dport: 80 },
  { proto: "tcp", sip: "203.0.113.9",  sport: 40001, dip: H, dport: 80 },
  { proto: "tcp", sip: "203.0.113.9",  sport: 40500, dip: H, dport: 80, syn: true },
  { proto: "tcp", sip: "198.51.100.7", sport: 40003, dip: H, dport: 80 },
  { proto: "tcp", sip: "198.51.100.7", sport: 40004, dip: H, dport: 22, syn: true },
  { proto: "udp", sip: "198.51.100.7", sport: 3335,  dip: H, dport: 9999 },
];
arrivals.forEach((p, i) => console.log(`${i + 1}. ${p.proto} ${(p.sip + ":" + p.sport).padEnd(19)}` +
  ` -> :${String(p.dport).padEnd(5)}${p.syn ? "SYN " : "    "}=> ${demux(p)}`));

আউটপুট:

1. udp 198.51.100.7:3333   -> :53       => S1 udp dns
2. udp 203.0.113.9:4444    -> :53       => S1 udp dns
3. tcp 198.51.100.7:40001  -> :80       => S3 tcp conn
4. tcp 198.51.100.7:40002  -> :80       => S4 tcp conn
5. tcp 203.0.113.9:40001   -> :80       => S5 tcp conn
6. tcp 203.0.113.9:40500   -> :80   SYN => S2 tcp listen (new connection request)
7. tcp 198.51.100.7:40003  -> :80       => none -> TCP RST
8. tcp 198.51.100.7:40004  -> :22   SYN => none -> TCP RST
9. udp 198.51.100.7:3335   -> :9999     => none -> ICMP port unreachable

লাইন ১–২: দুই আলাদা প্রেরক, কিন্তু একই socket S1 — UDP-র নিয়ম। লাইন ৩ আর ৫: উৎস port দুটিই 40001, তবু আলাদা socket (S3, S5), কারণ উৎস IP আলাদা। লাইন ৬: এই চার মানের কোনো সংযোগ নেই, কিন্তু segment-টি SYN আর port 80-এ listener আছে — তাই এটি নতুন সংযোগের অনুরোধ হিসেবে S2-তে গেল (handshake-এর বিস্তারিত পর্ব ২৯-এ)। লাইন ৭ সূক্ষ্ম: port 80-এ listener আছে, তবু RST! কারণ segment-টি SYN নয় — এটি এমন এক সংযোগের ডেটা, যার কথা সার্ভার জানে না (হয়তো সার্ভার রিস্টার্ট হয়েছে)। লাইন ৮: port 22-এ কেউ নেই, তাই SYN-এরও উত্তর RST. লাইন ৯: UDP-তে প্রত্যাখ্যানের ভাষা ICMP. বাস্তবের Linux kernel-ও মোটামুটি এই ক্রমে খোঁজে — আগে established সংযোগের hash table, তারপর listener-দের table.

একটি হিসাব: একজন client একটি সার্ভারে কতগুলো সংযোগ খুলতে পারে?

4-tuple-এর নিয়ম থেকে একটি সুন্দর numerical আসে। একটি client IP থেকে একটি নির্দিষ্ট সার্ভার IP:port-এ (যেমন 192.0.2.10:443) একসাথে যত সংযোগ, তাদের তিনটি মান একই — শুধু উৎস port আলাদা হতে পারে। Linux-এর ডিফল্ট ephemeral পরিসরে ২৮,২৩২টি port, তাই সেই জোড়ায় সর্বোচ্চ ২৮,২৩২টি একসাথে চলা সংযোগ (বন্ধ হওয়ার পরও কিছুক্ষণ TIME_WAIT-এ port আটকে থাকে, পর্ব ২৯)। কিন্তু সার্ভারের দিকে কোনো এমন সীমা নেই: তার port 443 একটিই, কিন্তু অপর প্রান্ত হতে পারে যেকোনো (IP, port) — তাত্ত্বিকভাবে ২৩২ × ২১৬ = ২৪৮টি আলাদা সংযোগ। বাস্তবে সীমা আসে memory আর file descriptor থেকে, port থেকে নয়। “একটি সার্ভার port-এ সর্বোচ্চ ৬৫,৫৩৫টি সংযোগ” — এটি একটি খুব প্রচলিত ভুল ধারণা।

৫ · Socket — প্রোগ্রাম আর OS-এর মাঝের দরজা

এ পর্যন্ত বারবার socket বলেছি। এটি আসলে কী? Transport layer চলে kernel-এর ভেতরে, আর অ্যাপ চলে user space-এ (পর্ব ০৩)। দুইয়ের মাঝে একটি দরজা লাগে — সেটাই socket. Unix-ধর্মী OS-এ “সবকিছুই ফাইল” দর্শন মেনে socket হলো একটি file descriptor — একটি ছোট পূর্ণসংখ্যা (3, 4, 5…), যা kernel-এর ভেতরের একটি socket-কাঠামোর দিকে নির্দেশ করে। তাই ফাইলের মতোই socket-এ read() আর write() চলে, আর close() দিয়ে বন্ধ হয়। File descriptor table কীভাবে কাজ করে, তা অপারেটিং সিস্টেম কোর্সের ফাইল সিস্টেম interface পর্বের অংশ ৫-এ, আর একই কম্পিউটারের প্রসেসের মধ্যে socket দিয়ে কথা বলা IPC পর্বে দেখতে পারেন। (Windows-এ socket একটি “handle”, Winsock API দিয়ে চলে — ধারণা একই, ফাংশনের নাম কিছুটা আলাদা।)

Socket তৈরির সময় অ্যাপ বলে দেয় কোন transport চায়: socket(AF_INET, SOCK_STREAM, 0) মানে IPv4-এর ওপর byte-স্রোত (TCP), আর SOCK_DGRAM মানে datagram (UDP). একটি TCP সার্ভারের কাজের ক্রম মোটামুটি এই — বিস্তারিত মডিউল ৭-এ (পর্ব ৪১–৪৫):

ফাংশনকে ডাকেকী করে
socket()দুই পক্ষনতুন socket, ফেরত দেয় একটি file descriptor
bind()সার্ভার (client ঐচ্ছিক)socket-কে একটি স্থানীয় IP:port-এ বাঁধে
listen()TCP সার্ভারsocket-কে listening socket বানায় — নতুন সংযোগ গ্রহণের জন্য প্রস্তুত
connect()TCP client (UDP-তেও চলে)অপর প্রান্ত ঠিক করে; TCP-তে handshake শুরু, bind না করা থাকলে OS ephemeral port দেয়
accept()TCP সার্ভারএকটি সম্পূর্ণ সংযোগ তুলে নিয়ে একটি নতুন connected socket ফেরত দেয়
getsockname(), getpeername()দুই পক্ষsocket-এর নিজের দিক আর অপর দিকের IP:port জানায়

এখানে সবচেয়ে জরুরি জিনিসটি হলো listening socket আর connected socket-এর পার্থক্য. অফিসের রিসেপশনের কথা ভাবুন: রিসেপশনিস্ট (listening socket) দরজায় বসে থাকেন, নতুন অতিথি এলে একজন কর্মকর্তাকে (connected socket) ডেকে তাঁর সাথে বসিয়ে দেন, আর নিজে আবার দরজায় ফেরেন। রিসেপশনিস্ট নিজে কারও সাথে মিটিং করেন না; প্রতিটি অতিথির জন্য আলাদা একজন। TCP সার্ভারেও তাই — listening socket কোনো ডেটা আদান-প্রদান করে না, শুধু নতুন সংযোগ নেয়; প্রতিটি সংযোগের ডেটা চলে তার নিজের connected socket দিয়ে। নিচের C প্রোগ্রাম এটি নিজের চোখে দেখায়, আর একই সাথে UDP-র “এক socket, অনেক প্রেরক” নিয়মটিও।

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define SA (struct sockaddr *)
static struct sockaddr_in A(unsigned short p) {       /* address 127.0.0.1:p */
    struct sockaddr_in a = {.sin_family = AF_INET, .sin_port = htons(p)};
    a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); return a;
}
static int sock(int type, unsigned short p) {         /* socket bound to 127.0.0.1:p */
    int s = socket(AF_INET, type, 0), on = 1; struct sockaddr_in a = A(p);
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
    if (bind(s, SA &a, sizeof a) < 0) perror("bind");
    return s;
}
int main(void) {
    struct sockaddr_in srv = A(8080), ua = A(5300), l, r; socklen_t n; char b;
    int lst = sock(SOCK_STREAM, 8080); listen(lst, 8);
    int c1 = sock(SOCK_STREAM, 50001), c2 = sock(SOCK_STREAM, 50002);
    connect(c1, SA &srv, sizeof srv); write(c1, "A", 1);
    connect(c2, SA &srv, sizeof srv); write(c2, "B", 1);
    for (int i = 1; i <= 2; i++) {                    /* accept() = one NEW socket per connection */
        int s = accept(lst, NULL, NULL); read(s, &b, 1);
        n = sizeof l; getsockname(s, SA &l, &n); n = sizeof r; getpeername(s, SA &r, &n);
        printf("tcp conn-%d fd=%d local %s:%u", i, s, inet_ntoa(l.sin_addr), ntohs(l.sin_port));
        printf(" peer %s:%u got '%c'\n", inet_ntoa(r.sin_addr), ntohs(r.sin_port), b);
    }
    printf("tcp listener fd=%d still on 127.0.0.1:8080\n", lst);
    int u = sock(SOCK_DGRAM, 5300), u1 = sock(SOCK_DGRAM, 50011), u2 = sock(SOCK_DGRAM, 50012);
    sendto(u1, "X", 1, 0, SA &ua, sizeof ua); sendto(u2, "Y", 1, 0, SA &ua, sizeof ua);
    for (int i = 0; i < 2; i++) {                    /* ONE udp socket receives from both */
        n = sizeof r; recvfrom(u, &b, 1, 0, SA &r, &n);
        printf("udp fd=%d got '%c' from %s:%u\n", u, b, inet_ntoa(r.sin_addr), ntohs(r.sin_port));
    }
}

আউটপুট:

tcp conn-1 fd=6 local 127.0.0.1:8080 peer 127.0.0.1:50001 got 'A'
tcp conn-2 fd=7 local 127.0.0.1:8080 peer 127.0.0.1:50002 got 'B'
tcp listener fd=3 still on 127.0.0.1:8080
udp fd=8 got 'X' from 127.0.0.1:50011
udp fd=8 got 'Y' from 127.0.0.1:50012

File descriptor নম্বরগুলো গল্পটা বলে। 0, 1, 2 আগে থেকেই stdin, stdout, stderr; তাই listener পেল 3, দুই client socket 4 আর 5 (ছাপা হয়নি), আর accept() দুবার ডাকায় এল দুটি নতুন socket, 6 আর 7. দুটিরই local দিক 127.0.0.1:8080 — listener-এর সাথে একই port! — কিন্তু peer আলাদা (50001, 50002), আর প্রত্যেকে ঠিক নিজের client-এর অক্ষর পেল ('A' আর 'B'). অর্থাৎ kernel চার মান দিয়ে segment আলাদা করেছে, আর listener (fd 3) কোনো ডেটা না ছুঁয়ে নিজের জায়গায় আছে।

UDP অংশে উল্টো ছবি: একটিমাত্র socket fd 8 দুই আলাদা প্রেরকের ('X' 50011 থেকে, 'Y' 50012 থেকে) datagram পেল, আর recvfrom() প্রতিবার প্রেরকের ঠিকানা জানিয়ে দিল। একটি কথা: আউটপুট প্রতিবার একই রাখতে client-দের port আমরা নিজেরা bind() করে দিয়েছি (50001, 50002…); সাধারণ প্রোগ্রামে client bind করে না, তখন connect() বা প্রথম sendto()-এর সময় kernel 32768–60999 থেকে একটি port বেছে দিত, যেমন আগের bash রানে 56396. সবকিছু loopback-এ, এক প্রসেসেই — কোনো বাইরের নেটওয়ার্ক লাগেনি।

৬ · নির্ভরযোগ্য পাঠানো, flow control আর congestion control — এক নজরে

TCP-র সবচেয়ে বড় প্রতিশ্রুতি নির্ভরযোগ্য ডেটা পাঠানো — অথচ নিচের IP কোনো প্রতিশ্রুতি দেয় না। অবিশ্বস্ত পথের ওপর বিশ্বস্ত সেবা গড়ার কৌশলগুলো আপনি পর্ব ১০-এ link স্তরের ARQ-তে দেখেছেন; transport স্তরে একই উপকরণ, শুধু মঞ্চ বড় (একটি তারের বদলে পুরো ইন্টারনেট):

  • বিট বদলেছে কি না ধরা: checksum (পর্ব ০৯) — TCP আর UDP দুটিই রাখে।
  • প্রাপক জানায় কী পেল: ACK. প্রেরক ACK না পেলে বোঝে কিছু হারিয়েছে।
  • হারানো ধরার ঘড়ি: timeout — নির্দিষ্ট সময়ে ACK না এলে আবার পাঠানো (retransmission).
  • দুবার বা উল্টো ক্রমে আসা চেনা: sequence নম্বর. TCP বাইট গুনে নম্বর দেয়, packet গুনে নয় (পর্ব ৩০)।
  • এক-একটি করে অপেক্ষা না করে একসাথে অনেক পাঠানো: pipelining আর sliding window — Go-Back-N আর Selective Repeat-এর ধারণা (পর্ব ১০)।

পার্থক্য হলো মঞ্চে: একটি তারে packet-এর ক্রম উল্টায় না আর RTT প্রায় স্থির; ইন্টারনেটে packet উল্টো ক্রমে বা অনেক দেরিতে আসতে পারে, আর RTT কয়েক মিলিসেকেন্ড থেকে কয়েকশো মিলিসেকেন্ড পর্যন্ত বদলায়। তাই TCP timeout মেপে মেপে ঠিক করে, আর sequence নম্বর রাখে ৩২ bit-এর — বিস্তারিত পর্ব ৩০-এ।

প্রশ্ন আসে: link স্তর যদি নির্ভরযোগ্য হয়, transport-এ আবার কেন? উত্তর পর্ব ০৩-এর end-to-end যুক্তি: প্রতিটি link নিখুঁত হলেও পথের কোনো router-এর memory-তে বিট বদলে যেতে পারে, router ভিড়ে packet ফেলে দিতে পারে, বা পুরো router বন্ধ হয়ে যেতে পারে। দুই প্রান্তের মধ্যে মিলিয়ে দেখা ছাড়া “সব পৌঁছেছে” নিশ্চিত হওয়ার উপায় নেই। Link স্তরের নির্ভরযোগ্যতা (যেমন Wi-Fi-র ACK, পর্ব ১৪) শুধু গতি বাড়ানোর একটি অপটিমাইজেশন।

দুটি আলাদা সমস্যা: flow control আর congestion control

দুটি নামই “গতি কমানো” বোঝায়, তাই পরীক্ষায় প্রায়ই গুলিয়ে যায়। কিন্তু সমস্যা দুটি সম্পূর্ণ আলাদা জায়গার:

Flow control — প্রাপককে বাঁচানো

প্রাপকের buffer ছোট বা অ্যাপ ধীরে পড়ে। প্রাপক নিজেই জানায় “আর এত বাইট জায়গা আছে” (receive window). চায়ের দোকানের ছেলেটি একবারে দশটি কাপই ধুতে পারে — তার বেশি পাঠালে ভেঙে পড়বে।

শেষ প্রান্তের সমস্যা · পর্ব ৩১

Congestion control — নেটওয়ার্ককে বাঁচানো

পথের কোনো router-এর queue উপচে পড়ছে। কেউ সরাসরি বলে দেয় না; প্রেরক packet হারানো বা delay বাড়া দেখে অনুমান করে গতি কমায় (congestion window). ফার্মগেটের জ্যামে সবাই ঢুকতে চাইলে কেউ নড়তে পারে না।

মাঝের নেটওয়ার্কের সমস্যা · পর্ব ৩২

একটি উদাহরণে পার্থক্যটা পরিষ্কার: একটি শক্তিশালী সার্ভার আর একটি শক্তিশালী ল্যাপটপ, কিন্তু মাঝের পথ ব্যস্ত — flow control-এর কোনো ভূমিকা নেই (প্রাপকের জায়গা অফুরন্ত), পুরো কাজ congestion control-এর। উল্টো দিকে, একই ঘরের দুটি যন্ত্র ১০ Gbps link-এ, কিন্তু প্রাপক একটি ছোট IoT বোর্ড — congestion নেই, কিন্তু flow control না থাকলে বোর্ডটি ডুবে যাবে। TCP দুটিই করে, আর যেকোনো মুহূর্তে পাঠাতে পারে দুই window-এর ছোটটির সমান ডেটা। UDP কোনোটিই করে না — তাই UDP-র ওপর চলা অ্যাপ (ভিডিও কল, QUIC) নিজেই congestion control বসায়, নাহলে সে নেটওয়ার্কের “অভদ্র” ব্যবহারকারী হয়ে অন্যদের ক্ষতি করে।

৭ · নতুন transport কেন এত কঠিন — ossification আর QUIC

ইন্টারনেটে প্রায় সব ট্রাফিক চলে মাত্র দুটি transport-এ — TCP (১৯৮১, RFC 793; ২০২২ সালে হালনাগাদ রূপ RFC 9293) আর UDP (১৯৮০, RFC 768). চার দশকে কি কেউ ভালো কিছু বানায়নি? বানিয়েছে — কিন্তু চালাতে পারেনি। কারণটি অংশ ১-এর সেই ব্যতিক্রম: মাঝের middlebox-গুলো transport header পড়ে।

SCTP (Stream Control Transmission Protocol) প্রথম মান হয় ২০০০ সালে (RFC 2960; পরে RFC 4960, আর ২০২২ সালে RFC 9260). এতে ছিল এক সংযোগে একাধিক স্বাধীন স্রোত (একটির ক্ষতি অন্যটিকে আটকায় না) আর multihoming (একাধিক IP দিয়ে একই সংযোগ) — আজকের অনেক চাহিদার আগাম সমাধান। মোবাইল আর টেলিফোন নেটওয়ার্কের ভেতরের signaling-এ এটি ব্যবহৃত হয়, আর ব্রাউজারের WebRTC data channel-এ এটি চলে — কিন্তু UDP-র ভেতরে মুড়ে। DCCP (RFC 4340, ২০০৬) চেয়েছিল UDP-র মতো অনির্ভরযোগ্য কিন্তু congestion control-সহ একটি transport — এটিও খোলা ইন্টারনেটে প্রায় ব্যবহৃত হয়নি বলেই সাধারণভাবে ধরা হয়। Multipath TCP (RFC 6824, ২০১৩; RFC 8684, ২০২০) নতুন protocol না বানিয়ে TCP-র option দিয়ে কাজ সারার পথ নিয়েছিল — ঠিক এই ossification-এর ভয়ে।

সমস্যাটা কোথায়? বাসার NAT router-কে port বদলাতে হয়, তাই সে শুধু TCP, UDP আর ICMP-র header চেনে। IP header-এর protocol ঘরে 132 (SCTP) দেখলে বেশিরভাগ NAT জানে না port কোথায় — packet ফেলে দেয়। Firewall “চিনি না, তাই আটকাই” নীতিতে চলে। Load balancer, ট্রাফিক পরিমাপের যন্ত্র — সবাই TCP-র নির্দিষ্ট আকার ধরে নেয়। এমনকি TCP-র ভেতরেও নতুন option যোগ করা ঝুঁকির: ২০১১ সালের একটি পরিচিত পরিমাপ-গবেষণা দেখিয়েছিল, উল্লেখযোগ্য সংখ্যক পথে middlebox অচেনা TCP option মুছে দেয় বা অস্বাভাবিক সংযোগ ফেলে দেয়। ইন্টারনেটের এই “জমে যাওয়া”কে বলে ossification. পরিণাম: যে সংযোগ চালু হবে কি না নিশ্চিত নয়, সেই protocol কোনো ব্রাউজার বা অ্যাপ ঝুঁকি নিয়ে ব্যবহার করে না — মুরগি আর ডিমের চক্র।

এর বাস্তববাদী জবাব QUIC (RFC 9000, ২০২১)। এটি নিজেকে UDP datagram-এর ভেতরে রাখে, কারণ UDP প্রায় সব NAT আর firewall পেরোয়। আর QUIC তার নিজের header-এর প্রায় সবকিছু এনক্রিপ্ট করে, যাতে middlebox-গুলো ভেতরে কী আছে দেখে নতুন কোনো “ধারণা” বানাতে না পারে — ভবিষ্যতে protocol বদলালেও যেন কেউ বাধা না দেয়। নির্ভরযোগ্যতা, congestion control, একাধিক স্রোত, TLS 1.3 — সবই QUIC-এর ভেতরে, user space-এর লাইব্রেরিতে, যা অ্যাপের সাথে দ্রুত হালনাগাদ করা যায়। HTTP/3 এর ওপরই চলে। QUIC কীভাবে এসব করে, তার পুরো গল্প পর্ব ৩৩-এ; এখানে শুধু এটুকু মনে রাখুন: নতুন transport চালাতে চাইলে আজ সেটা UDP-র ওপর বানানোই প্রায় একমাত্র ব্যবহারিক পথ।

৮ · কোন অ্যাপে TCP, কোনটিতে UDP — সিদ্ধান্তের টেবিল

“TCP ভালো, UDP খারাপ” বা “UDP দ্রুত, তাই সবসময় ভালো” — দুটোই অতি সরল কথা। সঠিক প্রশ্ন হলো: অ্যাপ হারানো ডেটা আবার চায় কি না, দেরিতে পৌঁছানো ডেটার কোনো দাম আছে কি না, আর নির্ভরযোগ্যতা নিজে বানানোর সামর্থ্য আছে কি না।

অ্যাপসাধারণতকেন
ওয়েব পাতা, API (HTTP/1.1, HTTP/2)TCP (+ TLS)প্রতিটি বাইট দরকার, ক্রম জরুরি
HTTP/3UDP-র ওপর QUICনির্ভরযোগ্যতা QUIC-এর ভেতরে; দ্রুত সংযোগ, স্রোত আলাদা (পর্ব ৩৩, ৩৭)
ফাইল ডাউনলোড, ইমেইল, SSH, ডেটাবেসTCPএকটি বাইট হারালেও ফল ভুল
DNS প্রশ্নUDP (বড় উত্তরে TCP)এক প্রশ্ন-এক উত্তর; handshake-এর এক RTT বাঁচে, হারালে অ্যাপ নিজেই আবার জিজ্ঞেস করে
ভিডিও কল, VoIP, অনলাইন গেমUDP (RTP, নিজস্ব protocol)দেরিতে আসা পুরোনো ফ্রেম অর্থহীন; আবার পাঠানোর চেয়ে বাদ দেওয়াই ভালো
লাইভ ভিডিও স্ট্রিমিং (YouTube, Facebook-এর মতো)প্রায়ই TCP-র ওপর HTTP (HLS/DASH), বা QUICকয়েক সেকেন্ড buffer থাকায় নির্ভরযোগ্যতা নেওয়া যায় (পর্ব ৪০)
DHCP, NTP, SNMPUDPছোট বার্তা; DHCP-তে client-এর তখনো IP-ই নেই, সংযোগ বানানো অসম্ভব
Broadcast বা multicastUDPTCP-র সংযোগ শুধু দুই প্রান্তের মধ্যে হয়

সংক্ষেপে একটি সিদ্ধান্তের ক্রম: (১) একসাথে অনেককে (broadcast/multicast) পাঠাতে হবে? → UDP. (২) প্রতিটি বাইট ঠিক ক্রমে লাগবে, আর কয়েকশো মিলিসেকেন্ড দেরি চলে? → TCP (বা QUIC). (৩) দেরিতে আসা ডেটা ফেলনা (কণ্ঠ, গেমের অবস্থান)? → UDP, ওপরে নিজের congestion control আর হালকা পুনরুদ্ধার। (৪) এক প্রশ্ন-এক উত্তরের ছোট বার্তা? → UDP, timeout আর পুনরায় চেষ্টা অ্যাপে। আর UDP বাছলে মনে রাখুন: যে নিরাপত্তা আর congestion control TCP+TLS এমনিতে দিত, তা এখন আপনার দায়িত্ব।

আরও গভীরে: Linux kernel TCP segment এলে আগে established সংযোগের একটি hash table-এ চার মান (আর network namespace) দিয়ে খোঁজে, না পেলে listener-দের table-এ। UDP-তে connect() করা socket-ও চার মান দিয়ে মেলে, আর না-জোড়া socket-এর চেয়ে বেশি নির্দিষ্ট বলে অগ্রাধিকার পায়। SO_REUSEPORT দিয়ে একাধিক প্রসেস একই port-এ আলাদা socket খুলতে পারে, আর kernel চার মানের hash দিয়ে নতুন সংযোগ বা datagram তাদের মধ্যে ভাগ করে দেয় — বড় সার্ভার এভাবে সব CPU core কাজে লাগায়। আর RFC 6056 ephemeral port অনুমানযোগ্য না রেখে এলোমেলোভাবে বাছার সুপারিশ করে, যাতে বাইরের কেউ সংযোগের চার মান আন্দাজ করে নকল segment ঢোকাতে না পারে।

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • Transport layer আর network layer-এর পার্থক্য? — network: host-to-host (IP ঠিকানা); transport: process-to-process (port), আর চলে শুধু end system-এ।
  • UDP আর TCP-র demultiplexing-এ কী পার্থক্য? — UDP socket চেনে (গন্তব্য IP, গন্তব্য port); TCP সংযোগ চেনে চার মান — উৎস ও গন্তব্যের IP আর port.
  • একই সার্ভারের port 80-এ দুই client-এর সংযোগ কীভাবে আলাদা থাকে? — উৎস IP বা উৎস port আলাদা, তাই চার মান আলাদা, তাই আলাদা connected socket.
  • Port-এর তিন পরিসর? — 0–1023 well-known, 1024–49151 registered, 49152–65535 dynamic/private (IANA); Linux-এর ডিফল্ট ephemeral 32768–60999.
  • Flow control আর congestion control-এর পার্থক্য? — প্রথমটি প্রাপককে রক্ষা করে (receive window), দ্বিতীয়টি নেটওয়ার্ককে (congestion window).

৯ · AI-এর যুগে port, socket আর transport বাছাই

“আমার অ্যাপের জন্য TCP না UDP?” বা “port 8080 কেন খুলছে না?” — AI-কে জিজ্ঞেস করলে দ্রুত উত্তর আসে। কিন্তু এই বিষয়ে AI-এর কিছু চেনা ভুল আছে, যা আত্মবিশ্বাসী ভাষায় বলা হয়:

AI-এর ভুলকেন ভুলকীভাবে ধরবেন
“একটি সার্ভার port-এ সর্বোচ্চ ৬৫,৫৩৫টি সংযোগ” বা “প্রতিটি সংযোগে সার্ভার নতুন port নেয়”সংযোগ চেনা যায় চার মানে; সার্ভারের port একটিই থাকেঅংশ ৫-এর C প্রোগ্রাম চালিয়ে getsockname() দেখুন — সব connected socket-এর local port একই
Ephemeral পরিসর সব OS-এ 49152–65535Linux-এর ডিফল্ট সাধারণত 32768–60999cat /proc/sys/net/ipv4/ip_local_port_range
“UDP-তে sequence নম্বর আর ACK আছে” বা “TCP bandwidth-এর নিশ্চয়তা দেয়”UDP header মাত্র চারটি ঘর; TCP কোনো গতি বা delay-এর নিশ্চয়তা দেয় নাRFC 768 (মাত্র তিন পাতা) আর RFC 9293 নিজে পড়ুন
netstat -tulpn-কে একমাত্র পথ বলাআধুনিক Linux-এ ss (iproute2); অনেক নতুন সিস্টেমে netstat ইনস্টলই থাকে নাman ss; Windows-এ Get-NetTCPConnection
“Port খুলছে না? firewall-এ সব port খুলে দিন” বা সার্ভারকে 0.0.0.0-এ bind করে ইন্টারনেটে উন্মুক্ত রাখাপুরো যন্ত্র আক্রমণের সামনে; শুধু দরকারি port আর দরকারি উৎস খুলতে হয়আগে ss -tlnp দিয়ে দেখুন প্রোগ্রাম আদৌ শুনছে কি না, কোন ঠিকানায়; তারপর একটি নির্দিষ্ট নিয়ম
বানানো RFC নম্বর বা ভুল সালভাষার মডেল বিশ্বাসযোগ্য শোনানো নম্বর বানাতে পারেrfc-editor.org-এ শিরোনাম মেলান: UDP 768, TCP 9293, port-এর নিয়ম 6335, QUIC 9000

AI-কে transport বাছাই বা port-এর সমস্যা দিলে প্রেক্ষাপট আর যাচাইয়ের শর্ত স্পষ্ট করে দিন:

আমি একটি অ্যাপ বানাচ্ছি: [অ্যাপের কাজ এখানে লেখো — যেমন লাইভ ক্লাসের অডিও, বা বিল পরিশোধের API]. ব্যবহারকারীরা মূলত মোবাইল ডেটায় থাকবেন, সার্ভার Linux-এ। ১. TCP, UDP না QUIC — প্রতিটির পক্ষে-বিপক্ষে বলো, আর আমার অ্যাপের কোন চাহিদা (নির্ভরযোগ্যতা, delay, নিরাপত্তা) কোন সিদ্ধান্তে নিয়ে যায় তা আলাদা করে দেখাও। ২. UDP বললে বলো congestion control আর encryption কে দেবে। ৩. সার্ভার কোন port-এ শুনবে আর কেন; firewall-এ ঠিক কোন নিয়ম লাগবে (সব port খোলার পরামর্শ দেবে না)। ৪. Linux-এ চালু অবস্থা যাচাইয়ের জন্য ss কমান্ড দাও, netstat নয়, আর প্রতিটি option-এর মানে বাংলায় লেখো। ৫. কোনো RFC-র উল্লেখ করলে নম্বর আর শিরোনাম দাও; নিশ্চিত না হলে স্পষ্ট বলো।

AI-এর transport পরামর্শ মানার আগে — চেকলিস্ট

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।

প্র ০১প্রথম দিকের নকশায় TCP আর IP ছিল একটিই protocol. পরে কেন দুটি আলাদা হলো, আর UDP কেন জন্মাল?

১৯৭৪ সালে Vint Cerf আর Bob Kahn যে প্রবন্ধে নেটওয়ার্কগুলো জোড়ার নকশা দেন, সেখানে একটিই “Transmission Control Program” ছিল — ঠিকানা দেওয়া, পথে পাঠানো, নির্ভরযোগ্যতা, ক্রম, সবই এক জায়গায়। ধারণাটি স্বাভাবিক ছিল: সেই সময়ের প্রধান অ্যাপ — remote login আর ফাইল পাঠানো — সবাই নির্ভরযোগ্য byte-স্রোত চাইত।

সমস্যা ধরা পড়ে যখন গবেষকেরা packet-এর ওপর কণ্ঠস্বর (packet voice) পাঠানোর পরীক্ষা করেন। প্রচলিত ইতিহাসে Danny Cohen-এর নাম আসে, যিনি যুক্তি দেন: কথার একটি টুকরো হারালে তা আবার পাঠানোর মানে হয় না — যখন পৌঁছাবে, তখন কথোপকথন এগিয়ে গেছে। এমন অ্যাপের জন্য নির্ভরযোগ্যতা উপকার নয়, ক্ষতি: হারানো packet-এর অপেক্ষায় পরের সব কথা আটকে যায়। অথচ ঠিকানা আর পথে পাঠানোর সেবা তারও দরকার।

সমাধান এল স্তর ভাগ করে। সত্তরের দশকের শেষে (১৯৭৮ সালের দিকে) নকশাটি দুই ভাগ হয়: IP — শুধু host থেকে host-এ best effort পৌঁছানো; আর তার ওপরে TCP — নির্ভরযোগ্যতা যার দরকার, তার জন্য। যার দরকার নেই, তার জন্য ১৯৮০ সালে এল UDP (RFC 768) — IP-র ওপর প্রায় কিছুই যোগ না করে, শুধু port আর checksum. পরে IPv4 (RFC 791) আর TCP (RFC 793) ১৯৮১ সালে প্রকাশিত হয়, আর ১ জানুয়ারি ১৯৮৩-এ ARPANET আনুষ্ঠানিকভাবে TCP/IP-তে চলে যায়।

এই বিভাজনই পর্ব ০৩-এর end-to-end নীতির একটি জীবন্ত উদাহরণ: নেটওয়ার্কের মাঝখানে (IP) সবার জন্য দরকারি ন্যূনতম সেবা, আর অ্যাপ-নির্ভর সেবা (নির্ভরযোগ্যতা) প্রান্তে, ঐচ্ছিকভাবে। চার দশক পরে QUIC-ও ঠিক এই সুবিধা নিচ্ছে — UDP-র সরলতার ওপর দাঁড়িয়ে নিজের মতো নির্ভরযোগ্যতা বানাচ্ছে।

মূল উপলব্ধি: একটি স্তরে সবকিছু রাখলে সেই স্তর সব অ্যাপের ওপর নিজের পছন্দ চাপিয়ে দেয়। TCP আর IP-কে আলাদা করে, আর UDP-কে “প্রায় খালি” transport রেখে, ইন্টারনেট এমন অ্যাপের জন্যও জায়গা রেখেছিল যেগুলো তখনো কল্পনাও করা হয়নি।

প্র ০২Port নম্বর কে ঠিক করে, “1024-এর নিচে বিশেষ অধিকার লাগবে” নিয়ম কোথা থেকে এল, আর আজ সেই নিয়মের নিরাপত্তা-মূল্য কতটুকু?

ইন্টারনেটের প্রথম দুই দশকে নম্বর-তালিকা রাখার কাজটি প্রায় এককভাবে করতেন Jon Postel — কোন protocol কোন port পাবে, তার তালিকা “Assigned Numbers” নামে RFC আকারে প্রকাশিত হতো (শেষটি RFC 1700, ১৯৯৪)। পরে এই দায়িত্ব IANA-র নামে প্রতিষ্ঠানিক রূপ পায়, আর ২০০২ সালে RFC 3232 জানিয়ে দেয় যে তালিকাটি এখন থেকে অনলাইন ডেটাবেসে থাকবে, RFC-তে নয়। ২০১১ সালের RFC 6335 আজকের তিন ভাগ (system, user, dynamic) আর বরাদ্দের নিয়ম ঠিক করে।

“1024-এর নিচে বিশেষ অধিকার” নিয়মটি এসেছে BSD Unix থেকে। আশির দশকের বিশ্ববিদ্যালয়ের নেটওয়ার্কে কম্পিউটারগুলো পরস্পরকে বিশ্বাস করত, আর rlogin/rsh-এর মতো প্রোগ্রাম একটি সরল যুক্তি দিত: যদি সংযোগের উৎস port 1024-এর নিচে হয়, তবে অপর যন্ত্রের root-ই সেটা খুলেছে, তাই ব্যবহারকারীর নাম বিশ্বাস করা যায়। এটি তখনই দুর্বল ছিল — অন্য কারও কম্পিউটারের root হওয়া কঠিন নয়, আর যাঁর নিজের ল্যাপটপ, তিনিই তার root. এই প্রোগ্রামগুলো আজ SSH দিয়ে প্রতিস্থাপিত, কারণ SSH বিশ্বাস করে cryptography-কে, port নম্বরকে নয়।

তবু নিয়মটির একটি সীমিত মূল্য আজও আছে: একটি বহু-ব্যবহারকারীর সার্ভারে সাধারণ ব্যবহারকারী port 22 বা 443-এ নকল সার্ভার চালিয়ে অন্যদের ঠকাতে পারেন না। কিন্তু খরচও আছে — শুধু port 80-এ শোনার জন্য পুরো ওয়েব সার্ভার root হিসেবে চালানো ঝুঁকির। তাই Linux এখন সূক্ষ্ম পথ দেয়: শুধু CAP_NET_BIND_SERVICE ক্ষমতাটি দেওয়া, বা net.ipv4.ip_unprivileged_port_start বদলে সীমাটাই সরানো।

মূল উপলব্ধি: Port নম্বর একটি সমন্বয়ের প্রথা — সবাই যাতে জানে কোথায় খুঁজতে হবে। একে পরিচয় বা বিশ্বাসের প্রমাণ হিসেবে ব্যবহার করা ইতিহাসের একটি ভুল, যার সংশোধন হয়েছে cryptography দিয়ে।

প্র ০৩একটি বড় অফিসের proxy বা load balancer হঠাৎ “cannot assign requested address” ত্রুটি দিতে শুরু করল, অথচ CPU আর memory প্রায় খালি। 4-tuple-এর নিয়ম দিয়ে এর ব্যাখ্যা আর সমাধান কী?

এই ত্রুটি প্রায়ই ephemeral port ফুরিয়ে যাওয়ার লক্ষণ। একটি proxy (বা load balancer, বা microservice-এর gateway) ব্যবহারকারীর প্রতিটি অনুরোধের জন্য নিজে client হয়ে পেছনের সার্ভারে নতুন সংযোগ খোলে। ধরা যাক পেছনে একটিই সার্ভার, 10.0.0.20:8080. Proxy-র নিজের IP একটি। তাহলে সব সংযোগের চার মানের তিনটি স্থির — proxy IP, সার্ভার IP, সার্ভার port — পার্থক্য শুধু উৎস port-এ। Linux-এর ডিফল্টে ২৮,২৩২টি port, তাই একসাথে সর্বোচ্চ প্রায় ততগুলো সংযোগ।

আসল ফাঁদ হলো বন্ধ সংযোগ। TCP-তে যে প্রান্ত আগে বন্ধ করে, তার socket বন্ধের পর কিছুক্ষণ TIME_WAIT অবস্থায় থাকে (Linux-এ ৬০ সেকেন্ড) — যাতে পুরোনো সংযোগের দেরিতে আসা segment নতুন সংযোগে ঢুকে না পড়ে (পর্ব ২৯)। ওই সময় সেই চার মান আবার ব্যবহার করা যায় না। যদি proxy প্রতি সেকেন্ডে ৫০০টি ছোট অনুরোধের জন্য নতুন সংযোগ খুলে নিজেই বন্ধ করে, তবে যেকোনো সময় প্রায় ৫০০ × ৬০ = ৩০,০০০টি port TIME_WAIT-এ আটকে থাকে — ২৮,২৩২-এর বেশি! CPU অলস, অথচ নতুন সংযোগ খোলা যায় না।

সমাধানগুলো সরাসরি 4-tuple থেকে আসে। এক — সংযোগ পুনর্ব্যবহার: HTTP keep-alive বা connection pool দিয়ে একটি সংযোগে অনেক অনুরোধ পাঠানো; এটাই সবচেয়ে কার্যকর। দুই — চার মানের কোনো একটি বাড়ানো: proxy-তে একাধিক উৎস IP, বা পেছনের সার্ভারে একাধিক port বা একাধিক সার্ভার — প্রতিটি নতুন মান আরও ২৮,২৩২টি সম্ভাবনা দেয়। তিন — ephemeral পরিসর বড় করা (যেমন 1024–65535), যদিও তাতে অন্য সার্ভারের port-এর সাথে সংঘাতের ঝুঁকি বাড়ে। চার — Linux-এর tcp_tw_reuse-এর মতো সেটিং, যা নির্দিষ্ট শর্তে TIME_WAIT-এর চার মান আগেভাগে নতুন বহির্গামী সংযোগে ব্যবহার করতে দেয়; এটি বুঝে-শুনে ব্যবহারের জিনিস। TIME_WAIT-কে “বাগ” ভেবে জোর করে বন্ধ করা নয় — সেটি নির্ভরযোগ্যতার অংশ।

মূল উপলব্ধি: সংযোগের সীমা গোনা হয় চার মানের সম্ভাব্য সংমিশ্রণে, port-এর সংখ্যায় নয়। সমস্যা দেখা দিলে প্রশ্ন করুন — চার মানের কোনগুলো স্থির হয়ে গেছে, আর কোনটিকে বৈচিত্র্য দেওয়া যায়?

প্র ০৪নির্ভরযোগ্যতা নেটওয়ার্কের ভেতরে (প্রতিটি hop-এ) রাখা ভালো, নাকি প্রান্তে? পুরোনো X.25 নেটওয়ার্ক আর ইন্টারনেটের পথ তুলনা করে বলুন।

সত্তর আর আশির দশকে টেলিফোন কোম্পানিগুলোর তৈরি X.25 নেটওয়ার্ক নির্ভরযোগ্যতা রাখত নেটওয়ার্কের ভেতরে। প্রতিটি link-এ ACK আর retransmission, প্রতিটি switch-এ প্রতিটি virtual circuit-এর অবস্থা — যাতে প্রান্তের যন্ত্রগুলো (তখনকার সরল terminal) প্রায় কিছু না করেও নির্ভরযোগ্য সেবা পায়। যুক্তিটি তখনকার প্রেক্ষাপটে বোধগম্য ছিল: link-গুলো ছিল গোলমেলে, আর প্রান্তের যন্ত্রগুলো দুর্বল।

ইন্টারনেট উল্টো পথ নিল: IP-তে কোনো নিশ্চয়তা নেই, নির্ভরযোগ্যতা TCP-তে, দুই প্রান্তে। এর পক্ষে Saltzer, Reed আর Clark-এর ১৯৮৪ সালের end-to-end যুক্তি: প্রতিটি hop নির্ভরযোগ্য হলেও পুরো পথ নির্ভরযোগ্য হয় না — switch-এর memory-তে ভুল, switch বন্ধ হয়ে যাওয়া, বা প্রাপকের নিজের ডিস্কে লেখার ভুল কোনো hop-এর ACK ধরতে পারে না। তাই প্রান্তে যাচাই এমনিতেই লাগবে; তাহলে মাঝে আবার করে লাভ কী? মাঝে করলে প্রতিটি router-কে প্রতিটি সংযোগের অবস্থা রাখতে হয় — router জটিল আর দামি হয়, আর একটি router বন্ধ হলে তার ভেতরের সব সংযোগ মারা যায়।

ইন্টারনেটের নকশার সবচেয়ে বড় সুবিধা ছিল নমনীয়তা আর টিকে থাকা: router অবস্থাহীন, তাই একটি বন্ধ হলে packet অন্য পথে যায়, আর দুই প্রান্তের TCP কিছু টেরও পায় না (শুধু কয়েকটি retransmission). নতুন অ্যাপ নেটওয়ার্ক না বদলেই আসতে পারে। তবে যুক্তিটি “মাঝে কখনো কিছু নয়” বলে না: যে link খুব বেশি গোলমেলে (Wi-Fi, মোবাইল রেডিও), সেখানে link-স্তরের retransmission (পর্ব ১৪) পুরো পথের retransmission-এর চেয়ে অনেক দ্রুত ক্ষতি সারায় — তাই সেটি থাকে, কিন্তু শুধু গতির অপটিমাইজেশন হিসেবে, শুদ্ধতার নিশ্চয়তা হিসেবে নয়।

মূল উপলব্ধি: শুদ্ধতার শেষ নিশ্চয়তা কেবল প্রান্তেই দেওয়া যায়; মাঝের নির্ভরযোগ্যতা হলো দরকারমতো যোগ করা গতি-বর্ধক। এই ভাগ ইন্টারনেটকে সরল, টেকসই আর উদ্ভাবনের জন্য খোলা রেখেছে।

প্র ০৫একটি নতুন transport protocol নকশা করে আপনি তা ইন্টারনেটে চালাতে চান। ossification-এর অভিজ্ঞতা থেকে কোন কোন নকশা-সিদ্ধান্ত নেবেন?

ইতিহাস প্রথম শিক্ষাটি স্পষ্ট করেছে: IP-র ওপর সরাসরি নতুন protocol নম্বর নিয়ে নামা প্রায় নিশ্চিত ব্যর্থতা। SCTP প্রযুক্তিগতভাবে চমৎকার ছিল, কিন্তু বাসার NAT তার port খুঁজে পায় না, firewall অচেনা বলে আটকায়, আর OS-এর kernel-এ সমর্থন থাকলেও প্রতিটি ব্যবহারকারীর যন্ত্রে নির্ভরযোগ্যভাবে থাকে না। তাই প্রথম সিদ্ধান্ত: UDP-র ভেতরে মুড়ে পাঠানো — যেমন QUIC, WebRTC-র SCTP, আর অনেক VPN (WireGuard) করেছে।

দ্বিতীয় শিক্ষা: middlebox যা দেখতে পায়, একদিন তার ওপর নির্ভর করবে। TCP-র header খোলা ছিল বলে middlebox-গুলো তার sequence নম্বর, option আর flag-এর “স্বাভাবিক” রূপ ধরে নিয়েছে, আর ভিন্ন কিছু দেখলে ফেলে দেয়। তাই দ্বিতীয় সিদ্ধান্ত: যত বেশি সম্ভব header এনক্রিপ্ট করা, শুধু রাউটিং আর সংযোগ চেনার জন্য ন্যূনতম অংশ খোলা রাখা। QUIC ঠিক এটিই করেছে। তৃতীয়ত, যা খোলা রাখতে হয়, সেখানে এলোমেলো মান মাঝে মাঝে পাঠানো (একে বলে “greasing”) — যাতে কোনো middlebox নির্দিষ্ট মানের ওপর নির্ভর করার অভ্যাস না গড়ে। TLS আর QUIC দুটিতেই এই কৌশল ব্যবহার হয়।

চতুর্থ সিদ্ধান্ত বিতরণের: kernel-এ না বসিয়ে user space-এর লাইব্রেরিতে রাখা, যাতে ব্রাউজার বা অ্যাপের হালনাগাদের সাথে protocol-ও হালনাগাদ হয় — OS বদলানোর জন্য বছরের পর বছর অপেক্ষা করতে না হয়। খরচ হলো কিছুটা বেশি CPU, যা পরে kernel আর হার্ডওয়্যারের সাহায্যে কমানো হচ্ছে। পঞ্চম, fallback: কিছু নেটওয়ার্ক UDP-ই আটকায় বা সীমিত করে, তাই ব্রাউজার QUIC ব্যর্থ হলে চুপচাপ TCP+TLS-এ ফেরে। নতুন protocol-কে পুরোনো পথের পাশাপাশি চলতে জানতে হয়।

মূল উপলব্ধি: আজ নতুন transport বানানো মানে শুধু ভালো অ্যালগরিদম নয় — ইন্টারনেটের বাস্তব যন্ত্রগুলোর সাথে কৌশলী সহাবস্থান: UDP-তে মোড়া, এনক্রিপ্ট করা, user space-এ, আর ব্যর্থ হলে পুরোনো পথে ফেরার ক্ষমতা।

অনুশীলন

খাতা-কলম নিন — চার মান আর port-এর পরিসর ধরে ধরে হিসাব করুন।

  1. হাতে trace (ক্লাসিক প্রশ্ন): সার্ভার C (192.0.2.10) port 80-এ একটি ওয়েব সার্ভার চালায়। Host A (198.51.100.7) থেকে দুটি সংযোগ, উৎস port 40001 আর 40002; host B (203.0.113.9) থেকে একটি, উৎস port 40001. (ক) C-তে সংযোগের জন্য কতগুলো socket, আর listener মিলিয়ে মোট কত? (খ) B থেকে C-তে যাওয়া segment আর C থেকে B-তে ফেরা segment-এর উৎস ও গন্তব্য port কী? (গ) সার্ভার যদি UDP port 80-এ একটি socket নিয়ে একই তিন প্রেরকের datagram পেত, কতগুলো socket সেগুলো পেত?

    (ক) তিনটি connected socket — (198.51.100.7, 40001), (198.51.100.7, 40002), (203.0.113.9, 40001) অপর প্রান্ত নিয়ে, তিনটির local দিকই 192.0.2.10:80. সাথে একটি listening socket, তাই মোট ৪টি। A-র প্রথম আর B-র সংযোগের উৎস port একই হলেও উৎস IP আলাদা বলে চার মান আলাদা।

    (খ) B → C: উৎস port 40001, গন্তব্য port 80. C → B: উৎস port 80, গন্তব্য port 40001 — ফেরার পথে দুটি অদলবদল হয়, IP ঠিকানাও তাই। (গ) একটিই socket; UDP শুধু (গন্তব্য IP, গন্তব্য port) = (192.0.2.10, 80) দেখে, তাই তিন প্রেরকের সবকিছু একই socket-এ, আর অ্যাপ recvfrom() দিয়ে প্রেরক আলাদা করে।

  2. হিসাব (ephemeral port আর সংযোগের সীমা): একটি Linux proxy-র একটি IP, ডিফল্ট ip_local_port_range = 32768 60999. (ক) একটি পেছনের সার্ভার 10.0.0.20:8080-এ একসাথে সর্বোচ্চ কতগুলো সংযোগ খোলা যায়? (খ) পেছনে ৪টি সার্ভার (ভিন্ন IP, একই port) থাকলে? (গ) পরিসর বদলে 1024 65535 করলে (ক)-এর উত্তর কত, আর এর একটি ঝুঁকি কী?

    (ক) পরিসরের port = ৬০,৯৯৯ − ৩২,৭৬৮ + ১ = ২৮,২৩২. তিনটি মান (proxy IP, সার্ভার IP, সার্ভার port) স্থির, শুধু উৎস port বদলায়, তাই সর্বোচ্চ ২৮,২৩২টি সংযোগ (বাস্তবে TIME_WAIT-এ আটকে থাকা port বাদ দিয়ে আরও কম)।

    (খ) প্রতিটি সার্ভার IP একটি আলাদা গন্তব্য, তাই একই উৎস port প্রতিটি সার্ভারের সাথে আলাদা করে ব্যবহার করা যায়: ৪ × ২৮,২৩২ = ১,১২,৯২৮টি। (Linux সাধারণত connect()-এর সময় port বাছলে এই পুনর্ব্যবহার করে; কিন্তু অ্যাপ যদি connect()-এর আগে নিজে bind() করে, তবে port একচেটিয়া হয়ে যেতে পারে।) (গ) ৬৫,৫৩৫ − ১,০২৪ + ১ = ৬৪,৫১২টি। ঝুঁকি: পরিসর এখন registered port-গুলো ঢেকে ফেলেছে, তাই কোনো client সংযোগ যদি ধরুন 3306 নিয়ে বসে থাকে, তবে MySQL চালু হতে পারবে না — দরকারি port ip_local_reserved_ports-এ সংরক্ষণ করতে হবে।

  3. আউটপুট অনুমান করুন: অংশ ৪-এর demultiplexing simulator-এ দুটি বদল করা হলো — (১) S1-এর lip: "*" বদলে lip: "127.0.0.1", আর (২) ৭ নম্বর আগমনের (198.51.100.7:40003 → :80) সাথে syn: true যোগ। লাইন ১, ২ আর ৭ কী ছাপবে?
    1. udp 198.51.100.7:3333   -> :53       => none -> ICMP port unreachable
    2. udp 203.0.113.9:4444    -> :53       => none -> ICMP port unreachable
    7. tcp 198.51.100.7:40003  -> :80   SYN => S2 tcp listen (new connection request)

    S1 এখন শুধু 127.0.0.1:53-এ বাঁধা, আর datagram-গুলোর গন্তব্য IP 192.0.2.10 — ipOk() মেলে না, তাই কোনো socket নেই। এটি বাস্তবের একটি খুব চেনা সমস্যা: “সার্ভার চলছে, অথচ বাইরে থেকে পাওয়া যাচ্ছে না” — কারণ প্রোগ্রাম শুধু loopback-এ bind করেছে (ss -uln-এ 127.0.0.1:53 দেখাবে, 0.0.0.0:53 নয়)। লাইন ৭: চার মানের সংযোগ এখনো নেই, কিন্তু এবার SYN আর port 80-এ listener আছে, তাই এটি নতুন সংযোগের অনুরোধ।

  4. কমান্ড লিখুন: একটি Linux সার্ভারে port 8080 নিয়ে সমস্যা। (ক) কোন কোন TCP socket শুনছে, সংখ্যায় আর প্রসেসের নামসহ — কমান্ড লিখুন। (খ) শুধু port 8080-এর ESTABLISHED সংযোগগুলো দেখান। (গ) Windows-এ (PowerShell) port 8080-এ কে শুনছে, তা কীভাবে দেখবেন?
    # (ক) TCP, listening, numeric, process — অন্য ব্যবহারকারীর প্রসেস দেখতে sudo লাগতে পারে
    ss -tlnp
    # (খ) শুধু port 8080-এর চালু সংযোগ (দুই দিকের)
    ss -tn state established '( sport = :8080 or dport = :8080 )'
    # (গ) Windows PowerShell (উদাহরণ)
    Get-NetTCPConnection -LocalPort 8080 -State Listen
    Get-Process -Id (Get-NetTCPConnection -LocalPort 8080 -State Listen).OwningProcess

    -p প্রতিটি socket-এর মালিক প্রসেস দেখায় (users:(("nginx",pid=…,fd=6))-এর মতো); নিজের নয় এমন প্রসেসের জন্য root লাগে। Local Address ঘরে 127.0.0.1:8080 দেখলে বুঝবেন প্রোগ্রাম শুধু নিজের যন্ত্রের জন্য শুনছে, 0.0.0.0:8080 বা *:8080 মানে সব interface-এ। পুরোনো সিস্টেমে netstat -tlnp একই কাজ করে, কিন্তু আধুনিক distro-তে সেটি প্রায়ই ইনস্টল থাকে না। Windows-এ পুরোনো পথ netstat -ano | findstr :8080, যার শেষ কলাম PID.

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি TCP segment সার্ভারে পৌঁছে ওয়েব সার্ভার প্রোগ্রামের কাছে যাচ্ছে — ঘটনাগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Network card frame পায়, link স্তর frame-এর header সরিয়ে IP packet ওপরে দেয়
  2. IP দেখে গন্তব্য ঠিকানা নিজের, আর protocol ঘরে 6 — ভেতরের segment TCP-কে দেয়
  3. TCP checksum যাচাই করে
  4. TCP চার মান (উৎস IP, উৎস port, গন্তব্য IP, গন্তব্য port) দিয়ে সংযোগের socket খোঁজে
  5. ডেটা সেই socket-এর receive buffer-এ জমা হয়, প্রোগ্রাম read() করে পায়

একটি UDP সার্ভার 192.0.2.10:53-এ একটি socket খুলে রেখেছে। Host X (198.51.100.7, উৎস port 3333) আর host Y (203.0.113.9, উৎস port 4444) দুজনেই সেখানে datagram পাঠাল। সার্ভারে কী ঘটে?

  • kernel দুই প্রেরকের জন্য দুটি নতুন socket তৈরি করে
  • দুটি datagram-ই একই socket-এ যায়; recvfrom() প্রতিটির উৎস ঠিকানা জানায়
  • দ্বিতীয় datagram বাতিল হয়, কারণ socket প্রথম প্রেরকের সাথে যুক্ত হয়ে গেছে
  • Y একটি ICMP port unreachable পায়

একটি ওয়েব সার্ভার 192.0.2.10:80-এ চলছে। একটি ল্যাপটপ (198.51.100.7) থেকে দুটি ব্রাউজার ট্যাব একই সময়ে সার্ভারে TCP সংযোগ খুলেছে। সার্ভার দুটি সংযোগের segment কীভাবে আলাদা করে?

  • প্রতিটি সংযোগের জন্য সার্ভার নিজের একটি নতুন port নেয়
  • উৎস IP ঠিকানা দেখে
  • চার মান — উৎস IP, উৎস port, গন্তব্য IP, গন্তব্য port — দিয়ে; এখানে উৎস port আলাদা
  • IP header-এর protocol ঘর দেখে

IANA-র শ্রেণিবিভাগ (RFC 6335) অনুযায়ী port 49152-এর পরিসর কোনটি?

  • Well-known (system) port
  • Registered (user) port
  • অবৈধ, কারণ port ৪৯,১৫১-এর বেশি হতে পারে না
  • Dynamic / private port

কোন সেবাটি TCP বা UDP — কোনোটিই দেয় না?

  • একটি নির্দিষ্ট সর্বোচ্চ delay বা ন্যূনতম bandwidth-এর নিশ্চয়তা
  • Port দিয়ে নির্দিষ্ট প্রোগ্রাম পর্যন্ত পৌঁছানো
  • Checksum দিয়ে বিট-ভুল ধরা
  • হারানো ডেটা আবার পাঠিয়ে ক্রমমতো পৌঁছানো

একটি শক্তিশালী সার্ভার একটি ছোট IoT বোর্ডে একই ঘরের দ্রুত, ফাঁকা link দিয়ে ডেটা পাঠাচ্ছে, আর বোর্ডটির buffer বারবার ভরে যাচ্ছে। TCP-র কোন ব্যবস্থা এই সমস্যার জন্য?

  • Congestion control
  • Flow control
  • Demultiplexing
  • Checksum

একটি Linux host-এর TCP port 22-এ কোনো প্রোগ্রাম শুনছে না, আর কোনো firewall নেই। বাইরে থেকে port 22-এ একটি SYN segment এলে সাধারণত কী হয়?

  • Host একটি ICMP port unreachable পাঠায়
  • Host SYN-ACK পাঠিয়ে সংযোগ খোলে
  • Host একটি TCP RST পাঠায়; client “connection refused” দেখে
  • Segment-টি port 80-এর listener-এর কাছে যায়

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. Network = host-to-host, transport = process-to-process. Transport চলে শুধু end system-এ; router IP পর্যন্ত দেখে, middlebox (NAT, firewall, load balancer) ব্যতিক্রম।
  2. TCP: সংযোগ, নির্ভরযোগ্য ক্রমমতো byte-স্রোত, flow আর congestion control. UDP: শুধু port আর checksum, বার্তার সীমানা রাখে। কেউই delay, bandwidth বা নিরাপত্তার নিশ্চয়তা দেয় না।
  3. Port ১৬ bit: 0–1023 well-known, 1024–49151 registered, 49152–65535 dynamic (IANA, RFC 6335); Linux-এর ডিফল্ট ephemeral 32768–60999 (২৮,২৩২টি)।
  4. Demux: UDP = (গন্তব্য IP, গন্তব্য port) → অনেক প্রেরক, এক socket; TCP = চার মান → প্রতিটি সংযোগের আলাদা socket. না মিললে UDP-তে ICMP port unreachable, TCP-তে RST.
  5. Socket = file descriptor. Listening socket শুধু নতুন সংযোগ নেয়, accept() প্রতিটির জন্য নতুন connected socket দেয়। নতুন transport-এর পথ আটকায় ossification — তাই QUIC UDP-র ওপর।

পরের পর্বে: transport-এর সবচেয়ে হালকা সদস্য — UDP. আট বাইটের header-এর প্রতিটি ঘর, checksum-এর pseudo-header, কেন DNS, ভিডিও কল আর গেম UDP বেছে নেয়, আর UDP-র ওপর অ্যাপ নিজে কীভাবে নির্ভরযোগ্যতা যোগ করে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান