Socket programming — TCP server - client, UDP server - client in Python
WHY does socket programming exist?
WHAT problem does it solve? Two processes that don't share memory (different machines, or just different programs on one machine) need to exchange data. The OS owns the network card. Sockets are the API the OS gives you to hand bytes to the network and receive bytes from it.
WHY two flavours (TCP / UDP)? Reliability costs latency. Sometimes you must get every byte in order (web pages, files) → TCP. Sometimes speed matters more than the odd lost packet (video calls, DNS, gaming) → UDP.

HOW the calls fit together (the "from scratch" mental derivation)
Don't memorize the call list — derive it from what each side must do.
A TCP server must: (1) create a socket, (2) claim an address so clients can find it → bind, (3) say "I'm willing to queue incoming calls" → listen, (4) actually pick up a call → accept (this returns a new socket for that one client), (5) read/write, (6) hang up → close.
A TCP client must: (1) create a socket, (2) dial → connect, (3) read/write, (4) close.
Worked Example 1 — TCP echo server + client
# ---- tcp_server.py ----
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 + TCP
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # reuse port quickly after restart
s.bind(('127.0.0.1', 9000)) # claim address
s.listen(5) # queue up to 5 pending connections
print("listening...")
conn, addr = s.accept() # BLOCKS until a client dials; conn = per-client socket
print("connected by", addr)
data = conn.recv(1024) # read up to 1024 bytes
conn.sendall(b"echo: " + data)# send back
conn.close()
s.close()# ---- tcp_client.py ----
import socket
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(('127.0.0.1', 9000)) # dial the server
c.sendall(b"hello") # send bytes (NOT str!)
print(c.recv(1024).decode()) # -> echo: hello
c.close()| Step | Why this step? |
|---|---|
setsockopt(... SO_REUSEADDR ...) |
Without it, restarting the server fast → "Address already in use" because the OS keeps the port in TIME_WAIT. |
bind(('127.0.0.1', 9000)) |
Server must own a known address so the client can target it. Client usually doesn't bind — OS picks an ephemeral port. |
listen(5) |
Turns the socket "passive". The 5 is the backlog = max half-/fully-formed connections waiting for accept. |
conn, addr = accept() |
Returns a second socket dedicated to this client. The original s stays free to accept others. |
conn.recv(1024) |
1024 is a max — TCP is a stream, so one recv may return less or merge multiple sends. |
sendall vs send |
send may transmit part of the data; sendall loops until all bytes are sent. |
Worked Example 2 — UDP echo server + client
# ---- udp_server.py ----
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 + UDP
s.bind(('127.0.0.1', 9001))
print("udp up...")
data, addr = s.recvfrom(1024) # get one datagram + sender's address
s.sendto(b"echo: " + data, addr)# reply to that exact address
s.close()# ---- udp_client.py ----
import socket
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.sendto(b"hi udp", ('127.0.0.1', 9001)) # no connect; address goes with the packet
print(c.recvfrom(1024)[0].decode()) # -> echo: hi udp
c.close()| Step | Why this step? |
|---|---|
SOCK_DGRAM |
Selects UDP: each sendto is one self-contained packet (a datagram). |
recvfrom returns (data, addr) |
We must learn who sent it, since there's no fixed connection — needed to reply. |
no accept/connect |
Connectionless: the address lives in each call, not in a setup handshake. |
One send = one recv |
Datagrams preserve message boundaries (unlike TCP's byte stream). |
Common mistakes (Steel-man + fix)
Recall Feynman: explain to a 12-year-old
Two computers want to talk. A socket is like a walkie-talkie you build in your program. TCP is like calling a friend: you dial, they pick up, and now whatever you say arrives in order and nothing gets lost — but setting up the call takes a moment. UDP is like shouting a message across a noisy playground: super fast, no setup, but some words might get lost or arrive jumbled. The server is the kid who waits at a fixed spot (a known port) so others know where to find them; the client is the one who walks over and starts talking.
Flashcards
What socket type constant gives TCP?
SOCK_STREAMWhat socket type constant gives UDP?
SOCK_DGRAMWhat does AF_INET specify?
Order of TCP server calls?
Order of TCP client calls?
Why does accept() return a new socket?
Which UDP calls replace send/recv?
sendto(data, addr) and recvfrom(bufsize) → (data, addr).Why does UDP have no listen/accept/connect?
What does the listen(n) argument mean?
accept.In TCP, what does recv returning b'' signal?
Difference: 3 sends in TCP vs UDP?
send vs sendall?
send may transmit only part of the data; sendall loops until everything is sent.Why use SO_REUSEADDR?
What type must socket data be?
.encode()/.decode() to convert from/to str).Which side usually skips bind?
Connections
- TCP three-way handshake — what
connect/accepttrigger under the hood. - UDP vs TCP tradeoffs — reliability vs latency.
- Ports and IP addressing — how (IP, port) identifies an endpoint.
- TIME_WAIT and SO_REUSEADDR — why ports linger after close.
- Message framing / length-prefix protocol — fixing TCP stream boundaries.
- select / asyncio for concurrent servers — handling many clients at once.
- DNS — a real-world UDP protocol.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, socket basically ek programmable "phone jack" hai aapke code ke andar — do programs ya do machines ke beech bytes bhejne ka rasta. OS ke paas network card hota hai, aur socket woh API hai jisse aap us card ko bytes de sakte ho ya le sakte ho. Do flavours hote hain: TCP aur UDP.
TCP ko samjho jaise phone call — pehle dial karo (connect), doosra side uthaye (accept), phir baat shuru. Reliable hai: saara data, sahi order mein, kuch lost nahi hota. Server ka order yaad rakho: socket → bind → listen → accept → recv/send → close. Important baat — accept() ek naya socket return karta hai jo sirf us ek client se baat karta hai, original wala dusre clients ke liye free rehta hai.
UDP jaise postcard hai — koi setup nahi, bas sendto se packet phenk do aur recvfrom se le lo. Fast hai par packet drop, duplicate ya reorder ho sakta hai. Isliye UDP mein listen/accept/connect nahi hota, kyunki address har packet ke saath jaata hai. Yahi sabse bada exam point hai: TCP byte stream hai (3 sends ek recv mein merge ho sakte hain), jabki UDP message boundaries preserve karta hai par reliability nahi deta.
Do galtiyan har baar hoti hain: (1) socket sirf bytes leta hai, string nahi — .encode()/.decode() lagao. (2) TCP mein recv agar b'' return kare to matlab doosra side ne connection band kar diya, EOF samajho. In dono ko yaad rakhoge to aadha topic clear hai. 80/20 rule: TCP ka call order aur stream-vs-datagram difference — bas yeh do cheez sabse zyada marks deti hain.