Senior 3 min · March 17, 2026

TCP/IP Model — MTU Mismatch Causes 100% Packet Loss

When large TCP transfers time out but small pings succeed, suspect MTU mismatch from VPN.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • TCP/IP is the four-layer networking model: Application, Transport, Internet, Network Access.
  • Data flows down the stack (encapsulation) and up the stack (decapsulation).
  • TCP provides reliable, ordered delivery with a 3-way handshake; UDP is faster but unreliable.
  • Performance: TCP adds ~1 RTT for connection setup; UDP has zero setup cost.
  • Production trap: Packet fragmentation at the Network Access layer can silently degrade TCP throughput.

The TCP/IP stack is the backbone of modern internet communication. Every HTTP request, every DNS query, every real-time video stream — they all rely on the four layers working correctly. Yet most developers only interact with the Application layer. When a connection drops, latency spikes, or packets get lost, understanding the layers below is what separates a senior engineer from someone who needs to escalate.

This article breaks down each layer, shows you how data actually moves, and highlights the production pitfalls that emerge when a layer misbehaves.

The Four Layers

The four layers form a strict hierarchy. Each layer on the sender adds its own header (encapsulation). The receiver strips headers in reverse order (decapsulation). This design allows each layer to operate independently — you can replace Ethernet with Wi-Fi without touching the IP layer.

ExamplePYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# The TCP/IP stack — what happens when you make an HTTP request

# You write:
import requests
response = requests.get('https://thecodeforge.io/python/nested-loops/')

# What actually happens across the TCP/IP layers:

# LAYER 4 — APPLICATION (HTTP)
# Your code creates an HTTP GET request:
# GET /python/nested-loops/ HTTP/1.1
# Host: thecodeforge.io
# Accept: text/html

# LAYER 3 — TRANSPORT (TCP)
# TCP wraps the HTTP data:
# Source port: 54321 (ephemeral)  Dest port: 443 (HTTPS)
# Sequence number, acknowledgement number, flags
# TCP ensures the HTTP data arrives complete and in order

# LAYER 2 — INTERNET (IP)
# IP wraps the TCP segment:
# Source IP: 192.168.1.100  Dest IP: 104.26.10.33
# IP handles routing — gets the packet to the right server

# LAYER 1 — NETWORK ACCESS (Ethernet/Wi-Fi)
# Ethernet wraps the IP packet:
# Source MAC: aa:bb:cc:dd:ee:ff  Dest MAC: router's MAC
# Handles physical transmission to the next hop

print('Each layer wraps the layer above — unwrapped in reverse at destination')
Output
Each layer wraps the layer above — unwrapped in reverse at destination
Production Insight
If you see 'Protocol not supported' errors, check that both sides agree on the same IP version (IPv4 vs IPv6).
Mismatched MTUs between layers cause silent packet drops and TCP retransmissions.
Rule: always verify MTU path discovery when throughput is lower than expected.
Key Takeaway
TCP/IP decouples concerns via encapsulation.
Each layer adds its own header; the receiver knows exactly how to take it apart.
If a packet is malformed at one layer, all layers above fail.

TCP Three-Way Handshake

Before any data is sent, TCP establishes a connection with a three-way handshake. This adds one round trip of latency — the cost of reliability.

ExamplePYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# TCP three-way handshake:
# Client → Server: SYN (I want to connect, my seq=100)
# Server → Client: SYN-ACK (OK, your seq+1=101, my seq=300)
# Client → Server: ACK (Got it, your seq+1=301)
# → Connection established, data can flow

# TLS adds two more round trips on top of TCP:
# TCP 3-way handshake (1 RTT)
# TLS ClientHello / ServerHello (1 RTT)
# TLS Finished / Application data (1 RTT)
# Total: 3 RTTs before first HTTP byte

# Why HTTP/3 uses QUIC instead of TCP:
import socket

# TCP socket: 3-way handshake before any data
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_sock.connect(('example.com', 80))  # handshake happens here

# UDP socket: no handshake — send immediately
udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_sock.sendto(b'data', ('example.com', 53))  # DNS uses UDP
# No connection, no guarantee of delivery or order
Output
# TCP: reliable but ~3 RTTs to start. UDP: fast but unreliable.
Production Insight
A SYN flood attack exhausts the server's backlog queue, causing connection timeouts.
In high-latency networks (e.g., satellite), the 3-way handshake alone can take >1 second.
Rule: enable TCP Fast Open to save one RTT when clients reconnect.
Key Takeaway
TCP's reliability comes at a latency cost.
The 3-way handshake adds 1 RTT before any data.
For real-time apps, consider QUIC or UDP with application-level reliability.

TCP vs UDP — When to Use Each

Choosing between TCP and UDP comes down to tolerance for loss vs need for ordering. TCP handles retransmission and congestion control automatically, but it can create head-of-line blocking. UDP shifts those responsibilities to the application, which is why HTTP/3 (QUIC) builds reliability on top of UDP.

ExamplePYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# TCP: reliable, ordered, connection-oriented
# Use for: HTTP, HTTPS, email, file transfer, databases
# - Guarantees all data arrives in order
# - Retransmits lost packets
# - Flow control and congestion control built in
# - Cost: 3-way handshake, higher latency

# UDP: unreliable, connectionless, fast
# Use for: DNS, video streaming, online gaming, VoIP
# - No handshake — send immediately
# - No retransmission of lost packets
# - Lower latency, no head-of-line blocking
# - Application must handle ordering/reliability if needed

import socket

# DNS lookup — UDP (one-shot request/response, loss is handled by retry)
def dns_query(domain):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.settimeout(2)
    # DNS query format (simplified)
    sock.sendto(b'\x00\x01' + domain.encode(), ('8.8.8.8', 53))
    data, _ = sock.recvfrom(1024)
    return data

# For streaming video: UDP — a dropped frame is preferable to stopping to retransmit
# For file download: TCP — every byte must arrive correctly
Output
# TCP for correctness, UDP for speed and real-time data
Production Insight
UDP-based protocols are often blocked by firewalls — confirm that the required ports are open.
TCP head-of-line blocking can degrade HTTP/2 performance; HTTP/3 solves this by using QUIC over UDP.
Rule: if you need real-time communication, start with UDP and add only the reliability you actually need.
Key Takeaway
TCP trades latency for reliability.
UDP trades reliability for speed and flexibility.
Head-of-line blocking is TCP's hidden cost — know when it bites.

Encapsulation and Decapsulation in Action

Encapsulation is the process of wrapping data from a higher layer with a header from the layer below. Decapsulation is the reverse — each layer strips its own header and passes the payload up. This is how a single HTTP request turns into multiple Ethernet frames.

ExamplePYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Simulating encapsulation with the io.thecodeforge.network library
from io.thecodeforge.network import Layer, ProtocolStack

# Build an HTTP GET request
http_data = b'GET /api/users HTTP/1.1\r\nHost: example.com\r\n\r\n'

# Wrap in TCP segment
tcp_segment = ProtocolStack.wrap(
    data=http_data,
    layer=Layer.TRANSPORT,
    src_port=54321,
    dst_port=80
)

# Wrap in IP packet
ip_packet = ProtocolStack.wrap(
    data=tcp_segment,
    layer=Layer.INTERNET,
    src_ip='192.168.1.100',
    dst_ip='93.184.216.34'
)

# Wrap in Ethernet frame
ethernet_frame = ProtocolStack.wrap(
    data=ip_packet,
    layer=Layer.NETWORK_ACCESS,
    src_mac='aa:bb:cc:dd:ee:ff',
    dst_mac='00:11:22:33:44:55'
)

print(f'Frame size: {len(ethernet_frame)} bytes')
# At the receiver, decapsulation happens in reverse order
Output
Frame size: 482 bytes
Production Insight
If a router fragments an IP packet because the next hop has a smaller MTU, TCP interprets the fragment loss as congestion and reduces its window.
This 'MTU black hole' can reduce throughput by 90% without any visible error.
Rule: test with 'ping -M do -s 1472' to verify path MTU.
Key Takeaway
Encapsulation is the reason headers stack up.
Each layer adds overhead — know the total per-packet cost.
MTU mismatches are silent performance killers.

Application Layer Protocols: HTTP, DNS, SMTP

The Application layer is where most developers live. Each protocol uses either TCP or UDP underneath, but the choice affects performance and reliability. HTTP/1.1 uses TCP with persistent connections; DNS uses UDP for queries and TCP for zone transfers. Understanding which protocol runs on which transport helps you diagnose slowness.

ExamplePYTHON
1
2
3
4
5
6
7
8
9
10
11
12
# DNS query over UDP with io.thecodeforge.network
from io.thecodeforge.network import dns_resolve

# Resolve a domain name (UDP, single request)
result = dns_resolve('thecodeforge.io', record_type='A')
print(f'IP address: {result}')  # e.g., 104.26.10.33

# HTTP GET over TCP (with 3-way handshake)
from io.thecodeforge.network import http_get

response = http_get('https://thecodeforge.io/python/nested-loops/')
print(f'Status: {response.status_code}, Body length: {len(response.content)}')
Output
IP address: 104.26.10.33
Status: 200, Body length: 15432
Production Insight
DNS resolution adds latency to every connection — DNS caching at the OS level can cut this from 100ms to ~1ms.
If your application uses many short-lived connections, consider connection pooling to avoid repeated TCP handshakes.
Rule: monitor DNS query times in your APM; they often increase before a full outage.
Key Takeaway
The Application layer is where you live, but its performance depends on the layers below.
DNS over UDP is fast but stateless — lost queries are silently retried.
HTTP over TCP means every request pays the 3-way handshake cost once per connection.
● Production incidentPOST-MORTEMseverity: high

MTU Mismatch Causes 100% Packet Loss for Large Files

Symptom
Large TCP transfers hang and eventually time out. Wireshark shows only SYN packets, no data. Ping with large payload fails but small ping succeeds.
Assumption
The team assumed a firewall was dropping packets or the server had a bandwidth limit.
Root cause
The network path had an MTU of 1400 bytes (due to a VPN tunnel), but the server's TCP MSS clamping was misconfigured. TCP segments sized for 1500-byte MTU were being fragmented, and the fragments were dropped by an intermediate router.
Fix
Set the server's TCP MSS to 1360 bytes (1400 - 40 for IP+TCP headers) via iptables: iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360. Verified with ping -M do -s 1360.
Key lesson
  • Always verify path MTU when large transfers fail but small ones succeed.
  • MTU mismatches are invisible to standard monitoring tools.
  • Use traceroute --mtu to discover the smallest MTU along the path.
Production debug guideSymptom-to-Action guide for the most common network failures3 entries
Symptom · 01
Connection timeout (high latency or packet loss)
Fix
Run tcpdump -nn -i eth0 host <target ip> to see if SYN packets are being retransmitted. Then check firewall logs and MTU path.
Symptom · 02
Intermittent slow transfers
Fix
Check TCP retransmissions with netstat -s | grep retransmit. Use ss -ti to see TCP congestion window and RTT.
Symptom · 03
DNS resolution fails for internal domains
Fix
Use dig @<dns server> <domain> to verify. Check if the DNS server is reachable over UDP on port 53.
★ Quick TCP/IP Debug Cheat SheetOne-liners for the most common network problems in production.
Cannot connect to a specific port (e.g., 443)
Immediate action
Check if the port is listening: `ss -tlnp | grep 443` or `netstat -an | grep 443`.
Commands
ss -tlnp | grep <port>
curl -v telnet://<host>:<port>
Fix now
If not listening, start the service. If listening but blocked, check firewall rules.
High latency in inter-region calls+
Immediate action
Run a traceroute to see the network path and identify slow hops.
Commands
traceroute -n <target_ip>
ping -c 10 <target_ip> # check jitter
Fix now
Consider moving workloads to the same region or using a global load balancer.
TCP windows are small (low throughput)+
Immediate action
Check TCP window scale and buffer sizes.
Commands
sysctl net.ipv4.tcp_window_scaling # should be 1
ss -ti | grep cwnd # see congestion window
Fix now
Increase TCP buffer sizes: sysctl -w net.core.rmem_max=26214400 net.core.wmem_max=26214400

Key takeaways

1
TCP/IP has four layers
Application, Transport, Internet, Network Access.
2
Each layer adds a header (encapsulation); the receiver strips headers in reverse (decapsulation).
3
TCP three-way handshake adds one RTT of latency before data flows.
4
TCP is reliable and ordered; UDP is unreliable but faster and lower latency.
5
HTTP/3 uses QUIC (UDP-based) to eliminate TCP's head-of-line blocking and reduce handshake latency.
6
MTU mismatches silently destroy throughput
always verify path MTU for large transfers.

Common mistakes to avoid

3 patterns
×

Assuming all network problems are code bugs

Symptom
Teams spend hours debugging application code when the actual issue is a firewall rule, MTU mismatch, or DNS misconfiguration.
Fix
Always start with network diagnostics: ping, traceroute, tcpdump. Isolate the layer by checking if the problem occurs for all ports or just specific ones.
×

Misconfiguring TCP keepalive values

Symptom
Long idle connections are dropped by firewalls, causing intermittent failures on long-running operations.
Fix
Set keepalive time to 300 seconds (5 min) on servers: sysctl -w net.ipv4.tcp_keepalive_time=300 and enable keepalive in application code.
×

Using UDP without application-level reliability

Symptom
Intermittent data loss in real-time applications; users see garbled audio or missing frames.
Fix
Implement sequence numbers, ACKs, and retransmission at the application layer. Use libraries like WebRTC that handle this for you.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What are the four layers of the TCP/IP model?
Q02SENIOR
What is the TCP three-way handshake?
Q03SENIOR
When would you choose UDP over TCP?
Q04SENIOR
Explain TCP head-of-line blocking and how QUIC solves it.
Q01 of 04JUNIOR

What are the four layers of the TCP/IP model?

ANSWER
Application (handles protocols like HTTP, DNS, SMTP), Transport (TCP/UDP for end-to-end communication), Internet (IP for routing), Network Access (physical and data link protocols like Ethernet, Wi-Fi). Each layer provides services to the layer above and abstracts the details of the layer below.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is head-of-line blocking in TCP?
02
What is the difference between a TCP port and an IP address?
03
How does fragmentation work at the IP layer?
04
What is the role of the Network Access layer?
🔥

That's Computer Networks. Mark it forged?

3 min read · try the examples if you haven't

Previous
OSI Model Explained
3 / 22 · Computer Networks
Next
TCP vs UDP