Networking fundamentals appear in almost every senior engineering interview. Whether you’re designing a system or debugging production, you need to explain how data moves from browser to server and back. This guide covers the most common networking interview questions with clear explanations and code.
HTTP Protocol Versions
HTTP/1.1 vs HTTP/2 vs HTTP/3
| Feature | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Transport | TCP | TCP | QUIC (UDP-based) |
| Multiplexing | No (one req/connection) | Yes (streams) | Yes (independent streams) |
| Head-of-line blocking | Yes | TCP-level only | No |
| Header compression | No | HPACK | QPACK |
| Server push | No | Yes | Yes |
| Connection setup | 1 RTT (+ TLS) | 1 RTT (+ TLS) | 0 RTT (resumed) |
HTTP_STATUS_CODES = {
# 2xx Success
200: "OK — request succeeded",
201: "Created — new resource created (POST)",
204: "No Content — success, no body (DELETE/PUT)",
206: "Partial Content — range request (streaming/resume)",
# 3xx Redirection
301: "Moved Permanently — update bookmarks/crawlers",
302: "Found — temporary redirect (keeps method)",
304: "Not Modified — use cached version (ETag/If-None-Match)",
307: "Temporary Redirect — preserves method (POST stays POST)",
308: "Permanent Redirect — preserves method",
# 4xx Client Errors
400: "Bad Request — malformed syntax",
401: "Unauthorized — authentication required",
403: "Forbidden — authenticated but not authorized",
404: "Not Found",
409: "Conflict — state conflict (duplicate, optimistic lock fail)",
410: "Gone — permanently deleted (SEO: tell crawlers to deindex)",
422: "Unprocessable Entity — validation failed",
429: "Too Many Requests — rate limit hit",
# 5xx Server Errors
500: "Internal Server Error",
502: "Bad Gateway — upstream server error",
503: "Service Unavailable — overloaded or down",
504: "Gateway Timeout — upstream timeout",
}
CACHE_CONTROL_PATTERNS = {
"immutable_asset": "public, max-age=31536000, immutable", # JS/CSS with hash
"api_response": "private, max-age=0, must-revalidate", # User-specific data
"public_page": "public, max-age=3600, stale-while-revalidate=86400",
"no_cache": "no-store", # Sensitive data
"cdn_cacheable": "public, s-maxage=86400, max-age=3600", # CDN caches longer
}
TCP vs UDP
"""
TCP (Transmission Control Protocol)
- Connection-oriented: 3-way handshake before data
- Reliable: ACKs, retransmission, ordering
- Flow control: receiver advertises window size
- Congestion control: slow start, AIMD
- Use: HTTP, email, file transfer, databases
UDP (User Datagram Protocol)
- Connectionless: fire and forget
- No reliability guarantees — dropped packets are lost
- Lower latency (no handshake, no ordering overhead)
- Use: DNS, video streaming, online gaming, VoIP, QUIC
TCP 3-way handshake:
Client Server
│──── SYN ──────────►│
│◄─── SYN-ACK ───────│
│──── ACK ──────────►│
│ [data flows] │
TIME_WAIT state (2*MSL ~4 minutes):
Server socket enters TIME_WAIT after FIN exchange.
Prevents reuse of the same port/IP combo during packet drain.
High connection rate? Set net.ipv4.tcp_tw_reuse=1 on Linux.
"""
import socket
def tcp_echo_server(host="127.0.0.1", port=9000):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))
s.listen(5)
while True:
conn, addr = s.accept()
with conn:
data = conn.recv(4096)
conn.sendall(data) # Echo back
def udp_server(host="127.0.0.1", port=9001):
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.bind((host, port))
while True:
data, addr = s.recvfrom(4096)
s.sendto(data, addr)
DNS Resolution
"""
DNS Resolution Chain for "www.techinterview.org":
Browser cache → OS cache → Recursive resolver (ISP/8.8.8.8)
→ Root nameserver (.) → TLD nameserver (.org)
→ Authoritative nameserver (techinterview.org NS records)
→ Returns A/AAAA record → cached at each level per TTL
Record types:
A → IPv4 address
AAAA → IPv6 address
CNAME → Canonical name (alias)
MX → Mail exchanger
TXT → Arbitrary text (SPF, DKIM, domain verification)
NS → Nameserver delegation
SOA → Start of authority (zone metadata)
PTR → Reverse DNS (IP → hostname)
TTL considerations:
Low TTL (60s): fast failover, high resolver load, slower lookups
High TTL (86400s): cached everywhere, slow to propagate changes
Strategy: lower TTL before planned migration, raise after
"""
import dns.resolver # dnspython library
def lookup_dns(domain: str):
resolver = dns.resolver.Resolver()
resolver.nameservers = ["8.8.8.8", "1.1.1.1"]
for record_type in ["A", "AAAA", "MX", "TXT"]:
try:
answers = resolver.resolve(domain, record_type)
for ans in answers:
print(f"{record_type}: {ans}")
except dns.resolver.NoAnswer:
pass
TLS 1.3 Handshake
"""
TLS 1.3 Handshake (1 RTT, vs 2 RTT for TLS 1.2):
Client Server
│── ClientHello ─────────────────►│
│ (supported ciphers, key share) │
│◄─ ServerHello + Certificate ────│
│ + CertificateVerify + Finished│
│── Finished ────────────────────►│
│ [Encrypted data flows] │
Key improvements in TLS 1.3 vs 1.2:
- Removed weak algorithms: RSA key exchange, RC4, 3DES, SHA-1
- Forward secrecy mandatory (ephemeral Diffie-Hellman)
- 0-RTT resumption: client sends data with first packet
(risk: replay attacks — only use for idempotent requests)
- Handshake encrypted sooner (hides certificate from passive observer)
Common vulnerabilities and mitigations:
BEAST → Fixed in TLS 1.2+ (CBC IV chaining)
POODLE → Disable SSL 3.0/TLS 1.0
BEAST → Mitigated by 1/n-1 record splitting
CRIME → Disable TLS compression
HSTS → Force HTTPS, prevent downgrade attacks
"""
import ssl, socket
def check_tls(hostname: str, port: int = 443):
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as raw:
with context.wrap_socket(raw, server_hostname=hostname) as tls:
cert = tls.getpeercert()
print(f"Protocol: {tls.version()}")
print(f"Cipher: {tls.cipher()}")
print(f"Subject: {dict(x[0] for x in cert['subject'])}")
print(f"Expires: {cert['notAfter']}")
Load Balancing Algorithms
import random
import time
from collections import defaultdict
from typing import List, Optional
class Backend:
def __init__(self, host: str, weight: int = 1):
self.host = host
self.weight = weight
self.active_connections = 0
self.healthy = True
self.response_times: List[float] = []
class LoadBalancer:
def __init__(self, backends: List[Backend]):
self.backends = backends
self._rr_index = 0
def healthy_backends(self) -> List[Backend]:
return [b for b in self.backends if b.healthy]
def round_robin(self) -> Optional[Backend]:
healthy = self.healthy_backends()
if not healthy:
return None
backend = healthy[self._rr_index % len(healthy)]
self._rr_index += 1
return backend
def least_connections(self) -> Optional[Backend]:
healthy = self.healthy_backends()
if not healthy:
return None
return min(healthy, key=lambda b: b.active_connections)
def weighted_round_robin(self) -> Optional[Backend]:
"""Servers with higher weight get proportionally more requests."""
healthy = self.healthy_backends()
if not healthy:
return None
pool = []
for b in healthy:
pool.extend([b] * b.weight)
return pool[self._rr_index % len(pool)]
def ip_hash(self, client_ip: str) -> Optional[Backend]:
"""Same client IP always routes to same backend (sticky sessions)."""
healthy = self.healthy_backends()
if not healthy:
return None
idx = hash(client_ip) % len(healthy)
return healthy[idx]
def p2c_least_latency(self) -> Optional[Backend]:
"""Power of Two Choices — pick 2 random, choose lower latency."""
healthy = self.healthy_backends()
if len(healthy) < 2:
return healthy[0] if healthy else None
a, b = random.sample(healthy, 2)
avg_a = sum(a.response_times[-10:]) / max(len(a.response_times[-10:]), 1)
avg_b = sum(b.response_times[-10:]) / max(len(b.response_times[-10:]), 1)
return a if avg_a <= avg_b else b
CORS and Security Headers
SECURITY_HEADERS = {
# Prevent MIME-type sniffing
"X-Content-Type-Options": "nosniff",
# Clickjacking protection
"X-Frame-Options": "DENY", # or SAMEORIGIN
# Force HTTPS for 1 year, include subdomains
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
# Control referrer info
"Referrer-Policy": "strict-origin-when-cross-origin",
# Content Security Policy — whitelist allowed sources
"Content-Security-Policy": (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline' https://cdn.example.com; "
"style-src 'self' https://fonts.googleapis.com; "
"img-src 'self' data: https:; "
"connect-src 'self' https://api.example.com"
),
# Permissions Policy (formerly Feature-Policy)
"Permissions-Policy": "camera=(), microphone=(), geolocation=(self)",
}
CORS_HEADERS = {
"Access-Control-Allow-Origin": "https://app.example.com", # Never * for credentialed
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Authorization, Content-Type, X-Request-ID",
"Access-Control-Max-Age": "86400", # Cache preflight for 24h
"Access-Control-Allow-Credentials": "true",
}
Frequently Asked Questions
What is the difference between HTTP/2 and HTTP/3?
HTTP/2 runs over TCP with multiplexed streams (no head-of-line blocking at HTTP layer, but TCP-level blocking remains). HTTP/3 runs over QUIC (built on UDP), eliminating TCP head-of-line blocking entirely. HTTP/3 also supports 0-RTT connection resumption for returning clients, reducing latency. QUIC handles connection migration (switching IPs without reconnecting).
What happens when you type a URL in a browser?
The browser checks DNS cache, then OS cache, then queries the recursive resolver. The resolver walks the DNS tree (root → TLD → authoritative nameserver) to find the A/AAAA record. The browser establishes a TCP connection (3-way handshake), performs TLS handshake (1 RTT for TLS 1.3), sends an HTTP GET request, receives the response, and renders the page.
What is the difference between TCP and UDP?
TCP is connection-oriented with guaranteed delivery, ordering, and flow control. UDP is connectionless with no delivery guarantee — packets may be lost, duplicated, or reordered. TCP suits HTTP, databases, and file transfers. UDP suits DNS, video streaming, online gaming, and VoIP where low latency matters more than perfect reliability.
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “What is the difference between HTTP/2 and HTTP/3?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “HTTP/2 runs over TCP with multiplexed streams (no head-of-line blocking at HTTP layer, but TCP-level blocking remains). HTTP/3 runs over QUIC (built on UDP), eliminating TCP head-of-line blocking entirely. HTTP/3 also supports 0-RTT connection resumption for returning clients, reducing latency. QUIC handles connection migration (switching IPs without reconnecting).”
}
},
{
“@type”: “Question”,
“name”: “What happens when you type a URL in a browser?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “The browser checks DNS cache, then OS cache, then queries the recursive resolver. The resolver walks the DNS tree (root → TLD → authoritative nameserver) to find the A/AAAA record. The browser establishes a TCP connection (3-way handshake), performs TLS handshake (1 RTT for TLS 1.3), sends an HTTP GET request, receives the response, and renders the page.”
}
},
{
“@type”: “Question”,
“name”: “What is the difference between TCP and UDP?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “TCP is connection-oriented with guaranteed delivery, ordering, and flow control. UDP is connectionless with no delivery guarantee — packets may be lost, duplicated, or reordered. TCP suits HTTP, databases, and file transfers. UDP suits DNS, video streaming, online gaming, and VoIP where low latency matters more than perfect reliability.”
}
}
]
}