Application Layer — Cheat Sheet
Computer Networks · 5 topics. Download the PDF or the Instagram carousel and share it.
HTTP/1.1 vs HTTP/2 vs HTTP/3
Each HTTP version tackles the bottlenecks of its predecessor: HTTP/2 multiplexes requests over one TCP connection; HTTP/3 eliminates TCP head-of-line blocking by running over QUIC (UDP).
- ✓HTTP/1.1: text-based, one request per connection (serial), 6 parallel connections as workaround.
- ✓HTTP/2: binary, multiplexed streams over one TCP connection, HPACK header compression.
- ✓HTTP/2 still has TCP-level HOL blocking — one lost packet stalls all streams.
- ✓HTTP/3: runs over QUIC (UDP), per-stream reliability, eliminates TCP HOL blocking.
- ✓HTTP/3 + QUIC enables 1-RTT handshake and 0-RTT for repeat connections.
- ✓gRPC requires HTTP/2; most CDNs now support HTTP/3.
// HTTP/1.1 — one outstanding request per connection
// Connection: keep-alive reuses TCP connection but requests are serial:
//
// Connection 1: GET /index.html → wait → response
// GET /style.css → wait → response (serial, HOL blocking)
//
// Browser workaround: open 6 connections per origin
// 6 connections × TLS handshake overhead = 6 × ~2 RTT = expensive
// HTTP/1.1 request format:
// GET /api/users HTTP/1.1
// Host: api.example.com
// Accept: application/json
// Connection: keep-alive
//
// Headers are plain text — verbose, repetitive across requests
// No header compression → ~500B overhead per request minimum
// Java HttpURLConnection (HTTP/1.1):
URL url = new URL("https://api.example.com/users");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
int status = conn.getResponseCode(); // blocks until response arrivesHTTPS & TLS Handshake
HTTPS = HTTP over TLS. TLS authenticates the server via certificates and establishes an encrypted session key using asymmetric cryptography — then switches to fast symmetric encryption for all data.
- ✓TLS provides confidentiality, integrity, and server authentication.
- ✓TLS handshake: asymmetric crypto establishes shared secret → symmetric keys derived for data.
- ✓TLS 1.3: 1 RTT handshake, DH-only key exchange, Perfect Forward Secrecy always enabled.
- ✓Certificate binds public key to domain name, signed by a trusted Certificate Authority.
- ✓mTLS requires both client and server to present certificates — used for microservice auth.
- ✓Perfect Forward Secrecy: each session uses a fresh key — past sessions safe even if private key is stolen.
// TLS 1.3 Handshake (1 RTT): // // Client Server // │ │ // │── ClientHello ─────────────────────────>│ // │ (TLS version, cipher suites, │ // │ client DH key share) │ // │ │ // │<── ServerHello ─────────────────────────│ // │ (chosen cipher, server DH key share, │ // │ Certificate, CertificateVerify, │ // │ Finished) ← all ENCRYPTED │ // │ │ // │── Finished ────────────────────────────>│ // │══════════════ Encrypted data ═══════════│ // Session key derivation (both sides independently compute same key): // client_secret = DH(client_private, server_public) // server_secret = DH(server_private, client_public) // client_secret == server_secret (Diffie-Hellman property) // Session key derived from this shared secret via HKDF // TLS 1.2 vs TLS 1.3: // TLS 1.2: 2 RTT, RSA key exchange (server decrypts with private key — no PFS) // TLS 1.3: 1 RTT, DH key exchange only (Perfect Forward Secrecy always on) // PFS = even if server private key is stolen later, past sessions cannot be decrypted
DNS — Domain Name System
DNS translates human-readable domain names into IP addresses. It is a globally distributed, hierarchical, cached database queried billions of times per second using a recursive resolution process.
- ✓DNS walks Root → TLD → Authoritative server hierarchy to resolve names to IPs.
- ✓Recursive resolver (8.8.8.8) does the hierarchy walk and caches results for TTL seconds.
- ✓Record types: A (IPv4), AAAA (IPv6), CNAME (alias), MX (mail), TXT (SPF/DMARC), SRV (services).
- ✓Low TTL enables fast failover; high TTL reduces DNS query load.
- ✓JVM caches DNS aggressively — tune networkaddress.cache.ttl for cloud environments.
- ✓Blue-green deployments use CNAME swaps; Route53 supports health-check-based automatic failover.
// DNS resolution for "api.example.com" (cache miss):
//
// 1. Your app asks OS resolver: "What is api.example.com?"
// 2. OS checks /etc/hosts → not found
// 3. OS checks local DNS cache → not found
// 4. OS queries recursive resolver (e.g. 8.8.8.8 or ISP resolver)
//
// Recursive resolver (8.8.8.8):
// 5. Queries Root server → "I don't know, ask .com TLD at 192.5.6.30"
// 6. Queries .com TLD server → "I don't know, ask ns1.example.com at 205.251.196.1"
// 7. Queries ns1.example.com (authoritative) → "api.example.com = 93.184.216.34, TTL=300"
// 8. Recursive resolver caches result for 300 seconds, returns to OS
//
// 9. OS caches result, returns to application
// 10. App connects to 93.184.216.34:443
//
// Total: ~100ms on first lookup, ~0ms on cache hit
// This is why DNS adds latency to first connections — connection pooling helps
// Java: DNS lookup
InetAddress addr = InetAddress.getByName("api.example.com");
System.out.println(addr.getHostAddress()); // 93.184.216.34
// JVM DNS cache — Java caches DNS results aggressively (30s default positive, forever negative)
// For cloud environments where IPs change, reduce cache TTL:
// java.security.Security.setProperty("networkaddress.cache.ttl", "10");WebSockets
WebSocket provides a full-duplex, persistent connection over a single TCP connection — enabling the server to push data to the client without polling, ideal for chat, live feeds, and collaborative apps.
- ✓WebSocket upgrades an HTTP/1.1 connection to a persistent, full-duplex channel via HTTP 101.
- ✓Frame header is 2–10 bytes — far lower overhead than HTTP for frequent small messages.
- ✓wss:// = WebSocket over TLS (use always in production).
- ✓Long-lived connections require careful resource management — prefer non-blocking I/O (Netty, WebFlux).
- ✓Scale-out requires sticky sessions or a pub/sub layer (Redis, Kafka) to route messages across servers.
- ✓SSE is simpler for server-push-only use cases (live feeds, progress) — uses plain HTTP.
// WebSocket Upgrade handshake:
// Client → Server:
// GET /chat HTTP/1.1
// Host: ws.example.com
// Upgrade: websocket
// Connection: Upgrade
// Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== ← random base64 nonce
// Sec-WebSocket-Version: 13
//
// Server → Client:
// HTTP/1.1 101 Switching Protocols
// Upgrade: websocket
// Connection: Upgrade
// Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= ← SHA-1 of key+"GUID"
//
// ═══ Connection is now WebSocket — HTTP is gone ═══
// WebSocket frame header (2–10 bytes):
// ┌────┬────────┬────────────────────────┐
// │FIN │ Opcode │ Payload Length + Mask │
// └────┴────────┴────────────────────────┘
// Opcodes: 0x1=text, 0x2=binary, 0x8=close, 0x9=ping, 0xA=pong
// Client→Server frames are masked (4-byte XOR mask); Server→Client are not
// Java WebSocket server (Spring Boot):
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatHandler(), "/chat").setAllowedOrigins("*");
}
}
public class ChatHandler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
session.sendMessage(new TextMessage("Echo: " + message.getPayload()));
}
}gRPC vs REST
REST uses HTTP/1.1 with JSON — human-readable, universally supported, but verbose. gRPC uses HTTP/2 with Protocol Buffers — binary, strongly typed, 5–10× faster, and supports bidirectional streaming.
- ✓gRPC uses HTTP/2 + Protobuf; REST typically uses HTTP/1.1 + JSON.
- ✓Protobuf payloads are 5–10× smaller and faster to serialise than JSON.
- ✓gRPC supports 4 patterns: unary, server streaming, client streaming, bidirectional.
- ✓gRPC requires HTTP/2 — complicates some load balancer and proxy setups.
- ✓Browsers cannot use gRPC natively — require gRPC-Web proxy (Envoy).
- ✓Common pattern: REST for public APIs, gRPC for internal microservice-to-microservice calls.
// user.proto — service definition
syntax = "proto3";
package user;
service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse); // Unary
rpc ListUsers(ListUsersRequest) returns (stream UserResponse); // Server streaming
rpc UpdateUsers(stream UpdateUserRequest) returns (UpdateSummary); // Client streaming
rpc Chat(stream ChatMessage) returns (stream ChatMessage); // Bidirectional
}
message GetUserRequest { string user_id = 1; }
message UserResponse {
string id = 1;
string name = 2;
string email = 3;
int64 created = 4;
}
// Compile: protoc --java_out=. --grpc-java_out=. user.proto
// Generates: UserServiceGrpc.java (stubs), UserProto.java (POJOs)
// Java gRPC server (Spring Boot with grpc-spring-boot-starter):
@GrpcService
public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(GetUserRequest req, StreamObserver<UserResponse> observer) {
UserResponse response = UserResponse.newBuilder()
.setId(req.getUserId())
.setName("Alice")
.setEmail("alice@example.com")
.build();
observer.onNext(response);
observer.onCompleted();
}
}