Skip to main content

Command Palette

Search for a command to run...

ক্লায়েন্ট-সার্ভার কমিউনিকেশন আসলে কীভাবে কাজ করে (Go এবং Unix Systems-এর মাধ্যমে দেখলে)

Published
4 min read
ক্লায়েন্ট-সার্ভার কমিউনিকেশন আসলে কীভাবে কাজ করে (Go এবং Unix Systems-এর মাধ্যমে দেখলে)
I

A highly motivated and experienced full-stack developer with a proven track record of developing and deploying web applications. Skilled in a range of programming languages and frameworks, as well as database technologies. Comfortable working in a fast-paced environment and able to adapt to new technologies quickly. A team player who is also able to work independently when required.

যখন আমরা Web 2.0 থেকে Web 3.0-তে শিফটের কথা বলি, সবচেয়ে basic যে জিনিসটা বুঝতে হবে সেটা হলো ক্লায়েন্ট-সার্ভার কমিউনিকেশন আসলে কীভাবে হয়। এটা শুধু theory না — এটা হলো web, APIs, আর distributed systems-এর backbone।

যদি তুমি networking আর operating systems-এর deeper role নিয়ে curious, কীভাবে এগুলো requests আর responses handle করে, তাহলে abstractions গুলো একটু সরিয়ে নিচের layers-এ কী হচ্ছে সেটা দেখাই ভালো।

এই exploration-এর জন্য আমি Go language choose করেছি, কারণ আমি এখন এর runtime আর goroutines নিয়ে deep dive করছি। এই দুটোই key জিনিস Go-তে server applications-এ concurrency handle করার জন্য। আমরা দেখবো কীভাবে একটা simple HTTP request তোমার browser থেকে Go server-এ যায়, Unix kernel দিয়ে, আর আবার ফিরে আসে।

Step 1: Request করা

শুরুটা হয় তুমি browser-এ (Chrome) একটা URL টাইপ করার সাথে (www.example.com) অথবা কোনো API endpoint hit করার সাথে (https://medium.com/p/b98de3906ea0/edit)। সেই request network দিয়ে transmit হয় আর eventually server-এর router-এ পৌঁছায়, যেটা সেটাকে server-এর Network Interface Card (NIC)-এর কাছে forward করে।

Step 2: NIC আর OS Kernel

NIC হলো server-এর hardware component যেটা incoming network signals গুলোকে data-তে convert করে যেটা operating system process করতে পারে।

এখানে দুইটা key জিনিস হয়:

  1. NIC request data গুলোকে RAM-এর receive buffer-এ রাখে।

  2. এটা kernel-কে (OS-এর heart) signal করে যে নতুন data এসেছে।

এখন kernel responsibility নেয়। এটা packet-এর port number দেখে বুঝে নেয় কোন socket এই data handle করবে। প্রতিটা socket একটা file descriptor (FD)-এর সাথে associated, আর kernel এই mapping গুলো তার file descriptor table-এ maintain করে। সঠিক socket identify করার পরে, kernel data গুলো সেই socket-এর receive buffer-এ রাখে আর তার FD-কে "ready" mark করে।

এই point-এ, kernel basically সবকিছু prepare করে ফেলেছে আর অপেক্ষা করছে application-এর (আমাদের case-এ Go runtime) pick up করার জন্য।

Step 3: Go Runtime আর Goroutines Scene-এ আসে

Go runtime constantly goroutines গুলো manage করে আর OS-এর সাথে তাদের interactions handle করে। ধরো আমাদের main goroutine একটা socket-এ listen করছে এভাবে:

rw, err = l.Accept()

এখানে যা হয়:

  1. Go runtime, netpoll mechanism দিয়ে, kernel-কে জিজ্ঞেস করে: "এই FD-তে data ready হলে আমাকে wake up করো।"

  2. Kernel, দেখে যে FD active, signal back করে: "হ্যাঁ, এই socket-এ data waiting আছে।"

  3. Go runtime তখন FD টাকে সেই goroutine-এর কাছে hand over করে যেটা এটার জন্য wait করছিল।

তো main goroutine request পায় আর l.Accept() call করে। এটা connection details retrieve করে আর request handle করার জন্য নতুন একটা goroutine spawn করে, আর main goroutine আবার sleep-এ চলে যায় (time.Sleep() 😴 এর মতো), পরের connection accept করার জন্য ready হয়ে।

Step 4: Go-তে Routing আর Handling

নতুন spawn হওয়া goroutine এখন request process করে। সাধারণত এটার মানে:

  1. Request টাকে router (mux) দিয়ে pass করা যেটা figure out করে কোন handler কোন requested path-এর জন্য (/about, /home, /info, etc.)।

  2. সঠিক handler function execute করা, যেটা response prepare করে।

handler function example:

// /hello
func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, World!")
}

// /about  
func aboutHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "I'm Sifat, blogger, CP'er, Golang enthusiast")
}

Go-তে handlers সাধারণত responses গুলো write buffer-এ write করে। সেখান থেকে data send buffer-এ place হয়।

Step 5: Kernel আর NIC Response Handle করে

যখন handler send buffer-এ write করে, kernel আবার notify হয়। Kernel response data গুলো ring buffer-এ move করে, যেটা NIC constantly monitor করে।

NIC এই data pick up করে, electromagnetic signals-এ convert করে (অথবা optical/electrical medium অনুযায়ী), আর relevant protocols (TCP/IP stack) follow করে network দিয়ে transmit করে। Eventually, client — তোমার browser অথবা API consumer — response receive করে।

কিছু Abstractions যেগুলো Note করার মতো

আমি readability-র জন্য কিছু parts simplify করেছি:

  • DNS resolution: Request server-এ পৌঁছানোর আগেই client domain name টাকে IP address-এ resolve করে।

  • TCP three-way handshake: Data flow হওয়ার আগে client আর server connection establish করে।

  • TLS/HTTPS: Connection secure হলে, encryption আর decryption আরেকটা layer of processing add করে।

  • Multiplexing & scheduling: Kernel একসাথে অনেক sockets handle করে, প্রায়ই epoll/kqueue mechanisms ব্যবহার করে, আর Go runtime goroutines গুলোকে OS threads-এর উপর multiplex করে। (Kernel শুধু বসে বসে sockets গুলো একটা একটা করে check করে না — সেটা painfully slow হতো। বরং এটা efficient mechanisms যেমন epoll (Linux) অথবা kqueue (BSD/macOS) use করে runtime-কে notify করে যখন কোনো socket-এ data ready থাকে। এটা old-school polling থেকে অনেক বেশি scalable।)

কেন এটা Important

এই layers গুলো বুঝলে তোমার অনেক clear idea হবে performance bottlenecks কোথায় হতে পারে, Go-এর goroutines-এর মতো concurrency models কীভাবে OS-এর সাথে কাজ করে, আর কেন network programming powerful হওয়ার সাথে সাথে tricky ও হতে পারে।

যখন তুমি abstractions গুলো সরিয়ে নেবে, client-server communication আর "magic black box"-এর মতো মনে হবে না বরং hardware (NIC), OS kernel, আর language runtimes (আমাদের case-এ Go)-এর মধ্যে well-coordinated dance-এর মতো মনে হবে।

Credit : Sifat99

This flow diagram makes it easier to grasp the concept at a glance.

link : https://excalidraw.com/#room=c0dd4b512241aa3d300d,Ip9a-ahFyVXja7xBJT4qDQ

16 views

More from this blog

Low Level Design: গভীর থেকে বোঝা এবং আয়ত্ত করা

ভূমিকা: কেন এই Article? তুমি হয়তো programming শিখেছ। Variable, loop, function, data structure - সব জানো। কিন্তু যখন একটা বড় system বানাতে বসো, তখন মনে হয় কোথা থেকে শুরু করব? কীভাবে organize করব? Code লিখতে লিখতে হারিয়ে যাও একটা maze-এ। এই feeling...

Oct 15, 202520 min read71
Low Level Design: গভীর থেকে বোঝা এবং আয়ত্ত করা

Go-তে Interface কীভাবে Code Decouple করে?

একটা HTTP Server দিয়ে পুরো ব্যাপারটা বুঝে নেওয়া যাক আমরা সবাই জানি Go একটা সিম্পল ল্যাঙ্গুয়েজ, কিন্তু interface নিয়ে অনেকেরই confusion থাকে। আজকে আমরা দেখব কীভাবে interface আসলে তোমার code-কে flexible এবং maintainable বানায়। একটা real-world HTT...

Oct 14, 202520 min read5
Go-তে Interface কীভাবে Code Decouple করে?

তোমার Project-এ Coupled Code কীভাবে খুঁজে বের করবে?

Coupled code খোঁজা মানে হচ্ছে তোমার codebase-এ এমন জায়গা খুঁজে বের করা যেখানে একটা অংশ আরেকটার উপর বেশি depend করছে। এটা একটা detective work — তুমি clue খুঁজবে, pattern দেখবে, এবং সমস্যা চিহ্নিত করবে। চলো step by step শিখি কীভাবে এটা করতে হয়। কেন ...

Oct 14, 202510 min read2

Go-তে Object (Struct Instance) তৈরির সম্পূর্ণ গাইড

Go programming শেখার সময় একটা জিনিস খুব তাড়াতাড়ি বুঝতে হয় - কীভাবে object তৈরি করতে হয়। অন্য language যেমন Java বা Python এ class আছে, কিন্তু Go-তে আছে struct। আর struct এর instance বানানোই হলো object তৈরি করা। আজকের এই blog এ আমরা দেখব Go-তে ob...

Oct 13, 202524 min read3
Go-তে Object (Struct Instance) তৈরির সম্পূর্ণ গাইড
I

Imran Hasan

61 posts

Full-stack developer with experience in developing and managing web applications. Skilled in React, Node.js, HTML, CSS, and JavaScript. Experience in managing website hosting and security.