UDP — connectionless-এর সরলতা
UDP: User Datagram Protocol
8-byte header-এর সবচেয়ে ছোট transport protocol — কী ছেড়ে দিলে কী পাওয়া যায়, ones'-complement checksum-এর হাতে-কলমে গণিত, আর কোন application কেন এই অনিরাপদ দেখানো পথটাই বেছে নেয়।
আগে এটা বুঝি
TCP আমরা এখনো পড়িনি, কিন্তু সবাই তার নাম শুনেছি — নির্ভরযোগ্য, ক্রমবিন্যস্ত, সংযোগ-ভিত্তিক। তার ঠিক উল্টো চরিত্রের protocol-টাই আজ: UDP (User Datagram Protocol) — যেটা IP-র উপর বসে মাত্র 8 byte header যোগ করে, আর তারপর হাত গুটিয়ে বসে থাকে।
উপমাটা ডাকব্যবস্থার। TCP হলো টেলিফোন কল — আগে রিং, দুই পক্ষ “হ্যালো” বলে সংযোগ নিশ্চিত করে, তারপর কথা, শেষে বিদায়; কেউ কথা শুনতে ব্যর্থ হলে “একবার বলো আবার”। UDP হলো ডাকযোগে পাঠানো পোস্টকার্ড — ঠিকানা লিখে ফেলে দিলেন, পৌঁছাবে-না-পৌঁছাবে জানা নেই, দুইটা পোস্টকার্ড উল্টো ক্রমে আসতে পারে, কিন্তু প্রতিটা পোস্টকার্ড একটা সম্পূর্ণ, আলাদা বার্তা — পরেরটার সাথে মিশে না।
আজকের প্রশ্ন তিনটা: (১) এই 8 byte-এ ঠিক কী আছে? (২) TCP-র সুবিধাগুলো ছেড়ে দিয়ে কেউ কী পায়? (৩) সবচেয়ে ব্যস্ত কিছু application — DNS, VoIP, game, এমনকি আধুনিক internet-এর QUIC — কেন ইচ্ছাকৃতভাবে এই “ঝুঁকিপূর্ণ” পথ বেছে নেয়?
মূল ধারণা
8-byte header — পুরো protocol এক নিঃশ্বাসে
UDP datagram-এর কাঠামো: IP header-এর ঠিক পরে 8 byte, তারপর application-এর data। ব্যাস, এই যা।
| Byte | Field | কাজ |
|---|---|---|
| 0–1 | Source Port | ফেরত ঠিকানা; দরকার না হলে 0 |
| 2–3 | Destination Port | কোন application-কে deliver করা হবে |
| 4–5 | Length | header+data মোট (ন্যূনতম 8) |
| 6–7 | Checksum | অখণ্ডতা পরীক্ষা (IPv4-তে optional, IPv6-তে বাধ্যতামূলক) |
IP ঠিকানা দেয় machine-পর্যন্ত delivery; port সেই delivery- কে machine-এর ভেতরের নির্দিষ্ট application-পর্যন্ত নিয়ে যায়। এই একটা ধারণাই UDP-র IP-র উপর সবচেয়ে বড় অবদান — বাকিটা প্রায় সব IP-রই সম্প্রসারণ।
যা ছেড়ে দেওয়া হলো — তালিকাটা মুখস্থ না, যুক্তিটা
TCP যা দেয়, UDP-র তালিকায় সেসবের জায়গায় শূন্য:
| সুবিধা | TCP | UDP | কার কাছে শূন্যটা ভালো |
|---|---|---|---|
| Delivery guarantee | হ্যাঁ, retransmit করে | না — lost = lost | যেখানে পুরনো data নতুনের চেয়ে অমূল্য: live video |
| Ordering | ক্রমে সাজিয়ে দেয় | আসার ক্রমেই | যেখানে সর্বশেষ মানই একমাত্র সত্য: game state |
| Flow control | receiver-কে চাপায় না | না | যেখানে হারানো packet-এর চেয়ে বিলম্ব ভয়ংকর |
| Congestion control | network-কে চাপায় না | না | যেখানে app নিজেই গতি সামলায় |
| Connection setup | 1 RTT handshake | 0 RTT | DNS-এর মতো এক request-এর জন্য handshake বাড়তি কর |
লক্ষ্য করুন ডান কলামের প্যাটার্ন: যেখানে তাজা data পুরনো data- র চেয়ে মূল্যবান, অথবা যেখানে এক-একটা exchange ছোট — সেখানেই UDP জেতে।
কারা কেন UDP
- DNS — এক প্রশ্ন, এক উত্তর, কয়েকশো byte। Handshake-এর খরচ উত্তরের চেয়ে বড় হয়ে যেত। (বড় উত্তরে TCP fallback — dns লেসনে বিস্তারিত)
- VoIP / live video — 200 ms আগের audio frame আজ পুনরায় পাঠিয়েও কাজে লাগে না; হারালে ছেড়ে দাও, পরেরটা আসছে
- Games — প্রতি টিকে সর্বশেষ position দরকার; পুরনো position retransmit করা অর্থহীন
- DHCP — client-এর এখনো IP address নেই, কোনো connection সম্ভবই না; broadcast দরকার
- QUIC — HTTP/3-র ভিত্তি: TCP-র reliability নিজের মতো userspace-এ পুনর্নির্মাণ করে, UDP-কে শুধু carrier বানায়
Datagram boundary — UDP-র সবচেয়ে অবমূল্যানুষীত গুণ
sendto() একবার ডাকলেন = এক datagram = receiver-এর recvfrom()
একবারে ঠিক সেই পুরো বার্তা। Boundary অক্ষত।
TCP-তে কিন্তু না — সেখানে write() দুইবার করলেন 100 byte আর
200 byte, receiver-এর read(4096) একবারে 300 byte-ই ফেরত দিতে
পারে, বা 50-50-200 ভাগে তিনবার — TCP মনেই রাখে না আপনার message
কোথায় শেষ হয়েছিল, সে শুধু ক্রমবিন্যস্ত byte-stream। সেই কারণেই
TCP-র উপর প্রতিটা protocol (HTTP সহ) নিজের framing নিজে আঁকে —
length prefix, delimiter, ইত্যাদি।
UDP-তে এই সমস্যাই নেই: datagram আসে হয় পুরোটা, নয় একদমই না (ছোট datagram কখনো আধা-আধা আসে না — IP fragmentation হলেও reassembly-র পর receiver পুরো datagram-ই দেখে)।
ভেতরে কী ঘটছে
Checksum-এর গণিত — ones’ complement
UDP checksum 16-bit word-এর উপর ones’ complement arithmetic-এ হিসাব হয় — ঠিক সেই সংখ্যা-পদ্ধতি যেটা আমরা computer-representation module-এর signed-integers লেসনে two’s complement-এর আত্মীয় হিসেবে দেখেছি। নিয়ম:
- Data-কে 16-bit word-এ ভাগ করো (অজোড় byte হলে শেষে 0x00 জোড়ো)
- সব word জোড় করো — carry হলে সেটা আবার নিচে যোগ করো (end-around carry)
- যোগফলের ones’ complement নাও — সেটাই checksum
হাতে-কলমে একটা ছোট উদাহরণ — তিনটা word: 0x4500, 0x003c,
0xf7ff:
4500
+ 003c
------
453c (carry নেই)
+ f7ff
------
13d3b 17-bit হয়ে গেল → carry bit (1) ফিরিয়ে যোগ করো:
3d3b
+ 1
------
3d3c checksum = ~0x3d3c = 0xC2C3Receiver একই যোগফল checksum-সহ বার করলে পায় 0xFFFF — একটা
bit-ও বদলালে 0xFFFF হবে না।
Pseudo-header: যোগফলের তালিকায় UDP header+data-র সাথে যোগ হয় আরও কিছু — IP-র থেকে নেওয়া source IP, destination IP, protocol (17) আর UDP length। এই ভুতুড়ে header wire-এ পাঠানো হয় না; শুধু হিসাবে ঢোকে। কেন? কারণ checksum তখন প্রমাণ করে দেয় datagram-টা সঠিক ঠিকানায়ই পৌঁছেছে — যদি NAT বা buggy router ভুল IP-তে পাঠিয়ে দেয়, receiver-এর checksum মিলবে না, datagram ফেলে দেওয়া হবে।
Broadcast আর multicast — TCP-র পৌঁছাতে না-পারা জায়গা
TCP connection মানেই দুইটা নির্দিষ্ট endpoint-এর মধ্যে state — তাই “সবাইকে একবারে বলো” TCP-তে সংজ্ঞাগতভাবেই অসম্ভব (হাজারটা আলাদা connection খুলে না হলে)। UDP-তে কোনো connection নেই বলে:
- Broadcast —
255.255.255.255বা subnet broadcast address- এ এক send, সবাই পায়। DHCP-র প্রথম ধাপ এভাবেই চলে: নতুন client- এর কারো address জানা নেই, তাই ঘরের সবাইকে চিৎকার করে জিজ্ঞেস করতেই হয় - Multicast —
224.0.0.0/4রেঞ্জের group address; শুধু subscribe করা সদস্যরা পায়। IPTV, আর একই LAN-এর service discovery (mDNS) এখানে দৌড়ায়
এই দুটোই UDP-র একচেটিয়া ভূমি — এবং একই কারণে attack-এরও (amplification, dns লেসনে দেখবেন)।
উদাহরণ
একটা আসল UDP datagram হাতে খোলা
একটা DNS query-র UDP datagram-এর IP-header-পরবর্তী অংশের hexdump (dns লেসনের প্রস্তুতি হিসেবেও কাজে লাগবে):
c3 5f 00 35 00 2c 8a b2 <- UDP header (8 byte)Field ধরে ধরে:
c3 5f source port = 0xc35f = 49999 (client-এর ephemeral port)
00 35 destination port = 53 (DNS)
00 2c length = 44 byte (8 header + 36 DNS message)
8a b2 checksum = 0x8ab2 (pseudo-header সহ হিসাব করা)তার পরের 36 byte DNS message। লক্ষ্যণীয় তিনটা জিনিস:
- Header-এ কোনো seq, কোনো ack, কোনো flag নেই — কোনো connection-এর ধারণাই নেই; প্রতিটা datagram স্বয়ংসম্পূর্ণ
- Length field-টা সরাসরি বলে দিচ্ছে boundary কোথায় — receiver
এক
recvfrom()-এ ঠিক 44 byte-ই পাবে - এই datagram হারালে DNS client নিজেই timeout মেরে আবার পাঠাবে — reliability-র দায়িত্ব এখানে application-এর, transport- এর নয়
Boundary বনাম stream — পাশাপাশি দুই জগৎ
একই দুইটা message পাঠলে দুই protocol-এ receiver যা দেখে:
sender: send("HELLO") send("WORLD")
UDP receiver: TCP receiver:
recvfrom() -> "HELLO" (5 byte) read() -> "HE" (2 byte)
recvfrom() -> "WORLD" (5 byte) read() -> "LLOWOR" (6 byte)
read() -> "LD" (2 byte)
দুইটা সম্পূর্ণ, আলাদা datagram তিন read, ভাঙা টুকরো —
boundary 100% সংরক্ষিত boundary-র কোনো তথ্যই নেইছবিতে
UDP-র স্তরে অবস্থান ও দায়িত্ব-বিভাজন
- ApplicationDNS, DHCP, QUIC — reliability দরকার হলে নিজেই বানায়
- UDPports + optional checksum — boundary সংরক্ষণ, বাকি কিছু না
- IPaddressing, routing, fragmentation — best effort
- LinkEthernet/Wi-Fi — hop-to-hop CRC
আর একটা datagram-এর জীবন — কোথায় কী হারাতে পারে, কে জানে না:
app UDP layer IP layer network
| | | |
|-- sendto() --->| | |
| |-- datagram ---->| |
| | (checksum) |-- route -------->|
| | | |-- হারাল? শেষ।
| | | |-- পৌঁছাল?
| | | | receiver UDP
| | | | checksum মিলল?
| ...কিছুই জানা গেল না... | | না হলে ফেলে দেয়নিজে চালিয়ে দেখুন
দুই terminal-এ UDP চ্যাট — boundary আর নীরবতা নিজের চোখে
ধাপ ১ — receiver চালু করুন প্রথম terminal-এ:
nc -u -l 9999 # macOS; Linux-এ কিছু build-এ: nc -u -l -p 9999ধাপ ২ — sender দ্বিতীয় terminal-এ:
nc -u 127.0.0.1 9999এখন sender-এ লিখুন hello এন্টার — receiver-এ সরাসরি ফুটবে।
এরপর এক লাইনে অনেক শব্দ লিখুন, এন্টার দিন, তারপর আলাদা
আলাদা ছোট ছোট লাইন কয়েকটা দ্রুত টাইপ করে পাঠান। Receiver-এ
দেখবেন: প্রতিটা এন্টার = একটা সম্পূর্ণ আলাদা লাইন — কোনোটা মেশেনি,
কোনোটা ভাগেনি। এটাই datagram boundary।
ধাপ ৩ — নীরব হারানো:
# receiver বন্ধ করে দিন (Ctrl-C), তারপর sender-এ আবার লিখুন:
# কিছুই হবে না — কোনো error, কোনো বার্তা নেই। UDP চুপ।Sender-কে মনেই হবে সব ঠিক আছে। এটাই production-এ UDP app-দের application-level timeout/retry রাখার কারণ।
ধাপ ৪ (ঐচ্ছিক) — wire-এ নিজের চোখে দেখুন (tcpdump-এর জন্য sudo লাগে; শেষ করে Ctrl-C):
sudo tcpdump -i lo0 -X udp port 9999 # macOS loopback
# Linux-এ: sudo tcpdump -i lo -X udp port 9999Output-এ UDP header-এর 8 byte আর তার পরে আপনার লেখা text-ই hex-এ দেখতে পাবেন — আজকের example section-এর হাতে-খোলা dump-এর সাথে মিলিয়ে পড়ুন।
loss নিয়ে সততার কথা: loopback interface-এ packet হারায় না — কার্নেলের ভেতরেই সব হয়। তাই “UDP-তে packet হারায়” দেখতে হলে বাস্তব network (Wi-Fi-তে দুই machine) দরকার, বা পরের build-এর মতো নিজেই drop সিমুলেট করতে হয়। এটাই localhost-এ UDP app টেস্ট করার সবচেয়ে বড় ফাঁদ।
প্রতিটা send ঠিক এক recv হয়ে আসে (boundary সংরক্ষিত), বন্ধ receiver-এ পাঠালে কোনো error-ই আসে না (connection নেই), আর loopback-এ packet loss হয় না — তাই loss-এর বাস্তবতা simulation ছাড়া অনুভব করা যায় না।
নিজে বানান
UDP time-server ও client — নিজের হাতে datagram design
- Server: UDP socket bind করে চিরকাল recvfrom করুন — কোনো accept, কোনো state নেই
- Request-এ sequence number রাখুন যাতে client চিনতে পারে কোন reply কোন প্রশ্নের
- Client: settimeout দিয়ে retry loop — হারালে আবার পাঠানো, এটাই app-level reliability
- Reply-তে server-এর টাইমস্ট্যাম্প ফেরত দিন — এক datagram-এই পুরো protocol
- Drop simulation যোগ করুন: প্রতি ৩-তম reply ইচ্ছাকৃতভাবে বাদ দিয়ে client-এর retry দেখুন
লক্ষ্য: দেখানো যে UDP-র উপর reliability বানানো সহজ — শুধু তা
transport-এ না রেখে application-এ রাখতে হয়। পুরো protocol:
client "TIME <seq>" পাঠায়, server "OK <seq> <unix-time>"
ফেরত দেয়।
Server (time_server.py):
import socket, time, random
DROP_EVERY = 0 # 3 দিলে প্রতি ৩-তম reply ইচ্ছাকৃত drop (demo)
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 3777))
print("UDP time-server on :3777 — কোনো connection, শুধু datagram")
n = 0
while True:
data, addr = s.recvfrom(512)
parts = data.decode(errors="replace").split()
# খারাপ/অজানা request-ও এক datagram-এই এসেছে — ব্যর্থতা একাই সীমাবদ্ধ
if len(parts) != 2 or parts[0] != "TIME":
continue
seq = parts[1]
n += 1
if DROP_EVERY and n % DROP_EVERY == 0:
print(f"{seq}: ইচ্ছাকৃত drop (demo)")
continue
reply = f"OK {seq} {time.time():.6f}"
s.sendto(reply.encode(), addr)
if __name__ == "__main__":
main()Client (time_client.py):
import socket, sys, time
def query(sock, seq, retries=3):
msg = f"TIME {seq}".encode()
for attempt in range(1, retries + 1):
sock.sendto(msg, ("127.0.0.1", 3777))
try:
data, _ = sock.recvfrom(512)
return data.decode(), attempt
except socket.timeout:
print(f" seq={seq}: timeout, retry {attempt}/{retries}")
return None, retries
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0.7)
for seq in range(1, 6):
t0 = time.monotonic()
reply, tries = query(s, seq)
if reply is None:
print(f"seq={seq}: FAILED — server কাছে নেই বা সব reply হারাল")
continue
rtt = (time.monotonic() - t0) * 1000
print(f"seq={seq}: {reply} (rtt={rtt:.1f} ms, tries={tries})")
time.sleep(0.3)
if __name__ == "__main__":
main()চালান:
python3 time_server.py # এক terminal-এ
python3 time_client.py # আরেকটায়এবার server-এ DROP_EVERY = 3 করে দুটোই আবার চালান — client-
এর timeout-retry লাইনগুলো দেখবেন। প্রতিটা reply-তে নিজের পাঠানো
seq ফিরে আসছে দেখে client নিশ্চিত হয় উত্তরটা তারই প্রশ্নের —
এই ছোট ট্রিকটাই আজকের ICMP লেসনের identifier+sequence প্যাটার্নের
প্রতিধ্বনি, এবং পরের লেসনের TCP seq/ack-র ভূতুড়ে পূর্বাভাস।
নিজে বাড়ান:
- Client-এ পরপর দ্রুত ৫টা request পাঠিয়ে reply গুলোর ক্রম উল্টে গেলে ধরুন (loopback-এ কষ্ট, কিন্তু delay যোগ করে সম্ভব)
- Server-এ প্রতি request-এ নতুন socket-এ reply দিয়ে দেখুন source port বদলালে client-এর কী হয়
- Broadcast যোগ করুন —
SO_BROADCASTসেট করে255.255.255.255-এ এক request, LAN-এর সব time-server একসাথে উত্তর দেবে
বাস্তব সিস্টেমে
বাস্তব জগতে UDP
QUIC / HTTP/3। আজ internet-এর ক্রমবর্ধমান অংশ QUIC-এর উপর চলে — যেটা TCP-র সব ভালো গুণ (reliability, congestion control, security) userspace-এ নিজে বানিয়ে UDP-র উপর বসিয়েছে। কেন? TCP kernel-এ বসে — এর বৈশিষ্ট্য বদলাতে OS upgrade লাগে; QUIC browser/app-এ বসে — প্রতি release-এ উন্নত হয়। আর UDP-র connectionless সরলতার কারণে middlebox-গুলো এতে হস্তক্ষেপ করতে পারে না।
VoIP আর WebRTC। ফোনকলে 300 ms পুরনো audio frame পুনর্জন্ম দেওয়ার কোনো অর্থ নেই — WebRTC তাই UDP-তে RTP চালায়, loss সামলায় codec-এর error concealment দিয়ে।
Games। প্রতি 16 ms-এ নতুন state — পুরনো state retransmit করলে খেলা আরও খারাপ হয়। তাই প্রায় সব real-time multiplayer game UDP: হারালে ছেড়ে দাও, client prediction দিয়ে ঢেকে দাও।
NTP। সময় সিঙ্কে এক request-এক reply — handshake-এর খরচই measurement-কে দূষিত করবে।
DNS amplification attack। UDP-র connectionless সরলতার অন্ধকার পিঠ: জাল source address দিয়ে ছোট request, বিশাল reply — victim-এর দিকে বন্দুক বানানো। TCP-তে handshake জাল address আটকে দেয়; UDP-তে কেউ আটকায় না। এজন্যই আজ open UDP resolver শিকার করা হয়।
DHCP। একটাই প্রোটোকল যেখানে UDP-র broadcast ক্ষমতা অপরিহার্য — IP-ই নেই এমন client-এর connection-এর প্রশ্নই ওঠে না।
যে ভুলগুলো সবাই করে
“UDP 'unreliable' মানে UDP-র data প্রায়ই হারায় — তাই খারাপ protocol।”
UDP কিছুই হারায় না — UDP কিছুই বাঁচায়ও না। Packet হারানোর কাজটা network করে, TCP আর UDP দুটোর ক্ষেত্রেই সমান হারে; পার্থক্য শুধু TCP সেটা লুকিয়ে retransmit করে, UDP সত্যি কথাটা বলে দেয়। “খারাপ” নয় — স্বচ্ছ। যে application হারানো সামলাতে জানে (live media, game), সে এই স্বচ্ছতা থেকেই কম latency পায়।
“UDP-তে congestion control-এর দরকার নেই, তাই আমার app-ও দেবে না।”
TCP-র congestion control internet-কে ১৯৮৮-এর collapse থেকে বাঁচায়েছিল — সেটা লেসন ১৩-এর গল্প। UDP-তে transport এটা দেয় না মানে দরকার নেই নয়; মানে দায়িত্ব application-এর। অসংযত UDP sender (বিশেষত video flood) একই path-এর TCP flow-গুলোকে চূর্ণ করে দেয় — এজন্যই RFC 8085 UDP application-দের congestion control মানার কথা বলে। QUIC ঠিক এই কারণেই নিজের congestion control বহন করে।
“UDP checksum সবসময় থাকে, মিললে data নিশ্চিত সঠিক।”
দুই ভাগে ভুল। এক: IPv4-তে checksum ঐচ্ছিক — 0x0000 লিখে পাঠানো datagram বৈধ। দুই: checksum যেকোনো corruption ধরে না — এটা 16-bit যোগফল, দুই bit উল্টে গেলে যোগফল আগেরটার সমানই হতে পারে। তীব্র অখণ্ডতা দরকার হলে application-level hash (যেমন আধুনিক storage/backup protocol-গুলোতে) দরকার।
“Connectionless মানে UDP-তে কোনো state-ই থাকে না।”
Transport layer-এ state নেই — ঠিক। কিন্তু বাস্তব ব্যবস্থায় state অন্যত্র জমে: NAT box প্রতিটা UDP flow-র mapping মনে রাখে (কিছু সময় পরে মুছে দেয় — দীর্ঘ UDP session-এর keepalive-এর কারণ), firewall rule তৈরি হয়, application নিজেই session/sequence রাখে। “Stateless” শব্দটা transport-এর সীমানার ভেতরেই সত্যি।
বুঝেছেন কি না দেখুন
1UDP header-র চারটা field-এর নাম ও byte-আকার বলুন। কোনটা বাদ
দিলেও UDP datagram এখনো valid থাকে?
স্মরণ
Source port (2), destination port (2), length (2), checksum (2)। Checksum বাদ দিলেও (IPv4-তে 0x0000 লিখে) datagram বৈধ; বাকি তিনটা অপরিহার্য — port ছাড়া delivery-র ঠিকানা নেই, length ছাড়া boundary জানা যায় না।
2TCP-র উপর একটা protocol-এ sender write() করেছে 100 byte,
তারপর সাথে সাথে আরও 200 byte। Receiver read(4096) একবার
ডাকলে কত byte পেতে পারে? একই জিনিস UDP-তে করলে?
প্রয়োগ
write() করেছে 100 byte,
তারপর সাথে সাথে আরও 200 byte। Receiver read(4096) একবার
ডাকলে কত byte পেতে পারে? একই জিনিস UDP-তে করলে?TCP: যেকোনো কিছু 1 থেকে 300-এর মধ্যে — একবারেই 300 পেতে পারে
(দুই write এক stream-এ মিশে), বা 100, বা একটু একটু করে; TCP
message-এর সীমানা মনে রাখে না। UDP: প্রথম recvfrom-এ ঠিক
100, দ্বিতীয়টায় ঠিক 200 — boundary সংরক্ষিত, মিশে না।
3DNS এক request-এক reply কেন TCP-তে না করে UDP-তে করে — তিনটা
আলাদা কারণে ব্যাখ্যা করুন। কখন DNS তবু TCP ধরে?
যুক্তি
(১) Handshake মানে এক বাড়তি RTT — ছোট প্রশ্নের জন্য উত্তরের চেয়ে খরচ বড়; (২) ছোট প্রশ্নের জন্য state তৈরি করে server resource (connection table) নষ্ট — DNS server লাখো client সামলায়; (৩) Timeout-retry এক লাইনের কাজ, পুরো transport টানার দরকার নেই। TCP ধরে যখন উত্তর বড় — পুরনো 512 byte সীমা ছাড়ালে (truncation flag) বা DNSSEC-সই বড় response-এ — সেখানে reliability-র মূল্য সার্থক।
4Ones’-complement যোগফল হলো 0x3D3C। Checksum field-এ কী লেখা
হবে? Receiver পুরো যোগফল checksum-সহ বার করলে কী পাবে?
প্রয়োগ
Checksum = যোগফলের complement = ~0x3D3C = 0xC2C3। Receiver
data+checksum সব যোগ করলে পাবে 0x3D3C + 0xC2C3 = 0xFFFF —
ones’-complement-এ এটাই “শূন্য”। যেকোনো এক bit বদলালে যোগফল
0xFFFF থাকবে না, datagram ফেলে দেওয়া হবে।
5একটা live score app-এ প্রতি সেকেন্ডে score update যায়। একটা update
হারালে পরেরটা ১ সেকেন্ডেই আসে। এই app-এর জন্য TCP না UDP — কোনটা
এবং কেন? যদি হঠাৎ নিয়ম হয় “একবার হারালেই ভুল score দেখাবে” —
উত্তর কি বদলাবে?
ডিজাইন
প্রথম ক্ষেত্রে UDP — হারানো update পরেরটায় স্বয়ংক্রিয়ভাবে সংশোধিত হয়, তাই retransmit-এর মূল্য নেই; আর TCP-র হেড-অব-লাইন ব্লকিং (এক lost packet সব পরেরটাকে আটকে রাখে) live update-এ বিশেষ ক্ষতিকর। দ্বিতীয় ক্ষেত্রে হারানো update মানেই চিরতরে ভুল তথ্য — reliability অপরিহার্য — তখন TCP, অথবা UDP-র উপর নিজের ack+retransmit (অথবা প্রতি update-এ সম্পূর্ণ বর্তমান state পাঠানো — তাহলে আবার UDP-ই যথেষ্ট)। মূল শিক্ষা: protocol নয়, হারানো data-র মূল্য সিদ্ধান্ত ঠিক করে।
6Pseudo-header wire-এ যায় না — তাহলে সেটা checksum-এ ঢুকিয়ে ঠিক
কী লাভ? NAT box IP address বদলালে UDP checksum-এর কী হয়?
যুক্তি
লাভটা হলো misdelivery ধরা: checksum এখন IP-র ঠিকানার উপরও গণনা হয় — ভুল machine-এ পৌঁছালে (routing bug, NAT ভুল) receiver-এর হিসাব মিলবে না, datagram ফেলে যাবে — ভুল application-এ পৌঁছাবে না। NAT address বদলালে checksum আর বৈধ থাকে না — তাই NAT box নিজেই পুনর্গণনা করে (এজন্যই NAT UDP-র checksum field-কে ছুঁয়ে ফেলে; এটা NAT-এর প্রতিটা UDP datagram-এ করা বাধ্যতামূলক কাজ)।
এরপর কী
এরপর কী
আপনি এখন দেখেছেন connectionless-এর সরলতা — এবং তার দাম। পরের লেসনে আমরা উল্টো মেরুতে যাব: TCP।
পরের লেসনে:
- তিন-ধাপের handshake — কেন ঠিক তিন ধাপ, দুই কেন নয় (একটা ৪০ বছরের পুরনো historical failure গল্পসহ)
- 32-bit sequence number, flag bitfield, window — TCP segment header-র প্রতিটা field
- পুরো state machine: LISTEN থেকে TIME_WAIT পর্যন্ত — আর কেন একটা connection বন্ধ হয়েও ৪ মিনিট মরে না
আজকের build-এ আপনি seq নিজের হাতে বানিয়েছিলেন — পরের লেসনে
দেখবেন kernel সেই কাজটা কীভাবে প্রতিটা byte-এ করে।
আরও পড়ুন
- RFC 768 — User Datagram Protocol — J. Postel (ISI) · UDP-র পুরো specification — মাত্র ৩ পাতা, ইতিহাসের সবচেয়ে ছোট গুরুত্বপূর্ণ RFC-গুলোর একটা
- TCP/IP Illustrated, Volume 1: The Protocols — UDP chapter — W. Richard Stevens · UDP header, checksum গণনা আর wire-level উদাহরণের প্রামাণ্য উৎস
- Computer Networking: A Top-Down Approach — Transport Layer — Kurose & Ross · UDP বনাম TCP-র তুলনামূলক কাঠামো আর checksum-এর গাণিতিক আলোচনা