TCP, IP, and UDP: Understanding Internet Transport Protocols
Compare TCP vs UDP, learn the three-way handshake, flow control, congestion control, and when to use each protocol for developers.
TCP, IP, and UDP: Understanding Internet Transport Protocols
The internet runs on protocols. TCP and UDP are the two main transport protocols that sit on top of IP. Understanding what they do and when to use each one matters for system design, networking, and debugging.
The HTTP/HTTPS protocol post covers application-layer protocols. This post goes deeper into the transport layer.
The Protocol Stack
Networking uses a layered model. Each layer handles specific responsibilities:
graph TB
A[Application Layer<br/>HTTP, DNS, SMTP] --> B[Transport Layer<br/>TCP, UDP]
B --> C[Internet Layer<br/>IP]
C --> D[Link Layer<br/>Ethernet, WiFi]
IP handles addressing and routing. TCP and UDP sit on top of IP, adding their own features. You rarely choose between TCP and UDP directly; you choose an application protocol that uses one or the other.
TCP: Transmission Control Protocol
TCP is connection-oriented. Before sending data, the client and server establish a connection. This connection stays open throughout the conversation and closes when done.
The Three-Way Handshake
TCP uses a three-way handshake to establish connections:
sequenceDiagram
participant Client
participant Server
Client->>Server: SYN (seq=x)
Server->>Client: SYN-ACK (seq=y, ack=x+1)
Client->>Server: ACK (ack=y+1)
Note over Client,Server: Connection established!
- Client sends SYN with a sequence number
- Server responds with SYN-ACK, acknowledging the client’s sequence number and sending its own sequence number
- Client sends ACK, acknowledging the server’s sequence number
This takes a full round trip before any data can be sent. HTTPS adds TLS on top, requiring more round trips.
Reliable Data Transfer
TCP guarantees that data arrives intact and in order. It does this through:
- Acknowledgments (ACKs) - Receiver confirms receipt of data
- Sequence numbers - Data is numbered so the receiver can reorder out-of-order packets
- Retransmission - If data is not acknowledged, it is retransmitted
// TCP guarantees (simplified)
const sender = {
sequence: 0,
send(data) {
const packet = { data, sequence: this.sequence };
this.sequence += data.length;
return packet;
},
};
const receiver = {
expectedSequence: 0,
receive(packet) {
if (packet.sequence === this.expectedSequence) {
this.expectedSequence += packet.data.length;
return { ack: packet.sequence + packet.data.length };
}
// Out of order - request retransmission
return { ack: this.expectedSequence };
},
};
Flow Control
TCP prevents the sender from overwhelming the receiver. The receiver advertises a window size indicating how much buffer space it has. The sender cannot send more than this window without receiving acknowledgments.
// Flow control window
const receiver = {
bufferSize: 65535,
usedBuffer: 0,
windowSize() {
return this.bufferSize - this.usedBuffer;
},
};
Congestion Control
TCP also prevents overwhelming the network. It uses algorithms like slow start, congestion avoidance, and fast retransmit to dynamically adjust sending rate.
graph LR
A[Slow Start] --> B[Congestion<br/>Avoidance]
A -->|"packet loss"| C[Reduce Rate]
B -->|"packet loss"| C
C --> A
Slow start begins with a small window and exponentially increases it until packets are lost. This probing helps TCP find the available bandwidth without causing congestion.
UDP: User Datagram Protocol
UDP is simpler than TCP. It is connectionless and does not provide reliability, ordering, or flow control. Data is sent as datagrams, and the sender does not wait for acknowledgment.
UDP Characteristics
- No connection establishment (zero latency)
- No ordering or sequencing
- No retransmission of lost packets
- Small header overhead (8 bytes vs TCP’s 20+ bytes)
// UDP is simple
const sender = {
send(data, address) {
const datagram = { data, destination: address };
// Send and forget - no acknowledgment
return datagram;
},
};
const receiver = {
receive(datagram) {
// Handle datagram - might be duplicate, might be missing
return datagram.data;
},
};
UDP Header
UDP has a minimal header:
+----------------+----------------+----------------+----------------+
| Source Port | Dest Port | Length | Checksum |
+----------------+----------------+----------------+----------------+
Four 16-bit fields. Source port is optional (set to 0 if not used). Length includes header and data. Checksum for error detection.
TCP vs UDP Comparison
| Feature | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented | Connectionless |
| Reliability | Guaranteed delivery | Best effort |
| Ordering | In-order delivery | No ordering |
| Speed | Slower (handshake, ACKs) | Faster (no overhead) |
| Header size | 20+ bytes | 8 bytes |
| Flow control | Yes | No |
| Congestion control | Yes | No |
When to Use TCP
TCP is the right choice when:
- You need all data to arrive intact
- Order matters (files, messages, documents)
- You can tolerate some latency
- You are building HTTP servers, email, file transfer
Most web traffic uses TCP. The reliability guarantees mean you do not have to handle missing or duplicate data yourself.
When to Use UDP
UDP works well when:
- Speed matters more than reliability
- Real-time applications (voice, video, gaming)
- You want minimal overhead
- Application-level error handling is sufficient
- Multicast or broadcast is needed
// Good UDP use cases
const videoStream = {
protocol: "UDP",
// Missing frames are less noticeable than delay
// Accept some packet loss for real-time playback
};
const voiceCall = {
protocol: "UDP",
// Prefer hearing the other person with small gaps
// Over hearing them perfectly but delayed
};
const dnsQuery = {
protocol: "UDP",
// Fast lookup matters more than perfect reliability
// DNS servers retry if no response
};
Port Numbers
Both TCP and UDP use port numbers to multiplex connections. Ports range from 0 to 65535. Well-known ports (0-1023) are reserved for common services:
| Port | Service | Protocol |
|---|---|---|
| 80 | HTTP | TCP |
| 443 | HTTPS | TCP |
| 53 | DNS | UDP (also TCP) |
| 22 | SSH | TCP |
| 25 | SMTP | TCP |
Your application can use any port above 1024. Node.js http.createServer() defaults to port 3000, for example.
Common Misconceptions
”UDP is always faster”
UDP avoids TCP overhead, but speed depends on the network. On a reliable local network, UDP can transmit faster. On the public internet with packet loss, TCP’s congestion control actually helps it perform well.
”TCP is for files, UDP is for video”
Many video streaming platforms use TCP. The overhead is acceptable, and TCP’s reliability ensures frames are not dropped. Real-time video calls often use UDP for lower latency, but they build their own reliability layer for important data.
”You always choose between TCP and UDP”
Usually your application protocol decides this for you. HTTP uses TCP. DNS usually uses UDP but switches to TCP for large responses. WebRTC uses UDP for media but TCP for signaling.
Connecting It All Together
The layers build on each other:
graph TB
A[Your Application] --> B[HTTP over TCP]
B --> C[TCP over IP]
C --> D[IP over Ethernet]
D --> E[Physical Network]
Each layer encapsulates the one below it. Your HTTP request becomes a TCP segment, then an IP packet, then an Ethernet frame.
Production Failure Scenarios
| Failure | Impact | Mitigation |
|---|---|---|
| TCP connection timeout | Requests hang; poor user experience | Set appropriate connection timeouts; implement retry logic |
| UDP packet loss | Missing data; application-level failures | Implement application-level acknowledgment and retransmission |
| Port exhaustion | Cannot establish new connections; service unavailable | Monitor connection counts; implement connection pooling; increase port range |
| SYN flood attack | Server overwhelmed with half-open connections | Use SYN cookies; implement rate limiting; use DDoS protection |
| NAT timeout | Long-lived connections break; clients appear disconnected | Send keepalive packets; use connection-oriented protocols when possible |
| MTU mismatch | Packets dropped; connectivity issues | Use Path MTU Discovery; set conservative MTU values |
| TCP congestion collapse | Network throughput drops dramatically | Use proper congestion control algorithms; implement traffic shaping |
| UDP amplification attack | Your servers used to attack others | Validate source addresses; restrict UDP responses; implement rate limiting |
Observability Checklist
Metrics
- TCP connection rate (new connections per second)
- Active TCP connections (concurrent connections)
- TCP connection failures (connection refused, timeout)
- Segment retransmission rate
- TCP buffer utilization (bytes in send/receive buffers)
- UDP packet rate (packets sent/received per second)
- UDP error rate (checksum failures, buffer overflows)
- Round-trip time (RTT) for TCP connections
- Throughput (bytes sent/received per second)
Logs
- Connection failures with source IP and port
- TCP reset packets (RST) received
- UDP packet checksum failures
- Connection timeouts
- Port exhaustion warnings
- Network interface errors
Alerts
- Connection failure rate exceeds 5%
- Retransmission rate exceeds 10%
- Active connections approach limits
- UDP error rate increases
- TCP RST rate spikes (potential attack)
- Network latency anomalies
Security Checklist
- Use TLS over TCP when encryption is needed (not raw TCP)
- Implement connection timeouts to prevent resource exhaustion
- Monitor for SYN flood attacks; enable SYN cookies
- Use firewall rules to restrict exposed ports
- Implement rate limiting on TCP/UDP services
- Validate UDP source addresses to prevent spoofing
- Use IPsec for network-level encryption when needed
- Monitor for unusual traffic patterns indicating attacks
- Implement connection tracking for stateful firewall rules
- Restrict broadcast and multicast traffic where not needed
Common Pitfalls / Anti-Patterns
Assuming UDP is Always Faster
UDP avoids TCP overhead but does not guarantee delivery or ordering.
// Problem: UDP with no reliability
const socket = dgram.createSocket("udp4");
socket.send(data, port, host, (err) => {
// No confirmation data arrived - you simply do not know
});
// Better: Implement acknowledgment
socket.send(data, port, host);
socket.on("message", (msg) => {
if (msg.toString() === "ACK") {
// Confirmed delivery
}
});
Ignoring TCP Connection Limits
Each TCP connection consumes file descriptors and memory.
# Check current connection limits
cat /proc/sys/net/core/somaxconn # Max pending connections
cat /proc/sys/fs/file-max # System-wide file descriptors
# Monitor active connections
ss -s
Not Handling Connection Termination Properly
Abruptly closing connections can cause data loss.
// Graceful close - ensure data is sent
socket.end(); // Send FIN after remaining data is sent
socket.on("close", () => {
// Connection fully closed
});
Building Custom Reliability on UDP When TCP Would Work
If you need reliable, ordered delivery, just use TCP.
// Problem: Building reliability on UDP
socket.on("message", (data) => {
// Must implement sequence numbers, acknowledgments, retransmission
// This is essentially reimplementing TCP
});
// Better: Just use TCP
const server = net.createServer((socket) => {
// Reliability built in
});
Quick Recap
Key Bullets
- TCP provides reliable, ordered, connection-oriented delivery with flow and congestion control
- UDP provides fast, unreliable, connectionless delivery without overhead
- TCP three-way handshake establishes connections; UDP sends immediately
- TCP uses acknowledgments, sequence numbers, and retransmission for reliability
- UDP header is 8 bytes; TCP header is 20+ bytes minimum
- Choose TCP when correctness matters; choose UDP when speed and low latency matter more
- Common TCP ports: 80 (HTTP), 443 (HTTPS), 22 (SSH), 25 (SMTP), 53 (DNS)
- DNS uses UDP port 53 for queries, TCP for zone transfers and large responses
Copy/Paste Checklist
# Check TCP connection states
ss -tunapl | grep -E "(State|Recv-Q|Send-Q)"
# Monitor TCP metrics
cat /proc/net/tcp
cat /proc/net/tcp6
# Check UDP statistics
cat /proc/net/udp
cat /proc/net/udp6
# Test TCP connection with netcat
nc -zv host.example.com 443
# Test UDP connectivity (limited)
nc -zvu host.example.com 53
# Check for open ports
ss -tunapl | grep LISTEN
# View TCP window sizes
cat /proc/sys/net/ipv4/tcp_rmem
cat /proc/sys/net/ipv4/tcp_wmem
# Test MTU
ping -M do -s 1472 example.com
Conclusion
TCP and UDP serve different needs. TCP provides reliability, ordering, and flow control at the cost of latency. UDP provides speed and simplicity at the cost of reliability guarantees.
Choose TCP when correctness matters more than speed. Choose UDP when speed matters more than perfect reliability, or when you want to build your own reliability layer on top.
For application-layer protocols, see the HTTP/HTTPS post. For DNS specifically, the DNS & Domain Management post covers name resolution in detail.
Category
Tags
Related Posts
HTTP and HTTPS Protocol: A Complete Guide to Web Communication
Deep dive into HTTP methods, status codes, headers, keep-alive, and protocol evolution. Understand HTTP/1.1, HTTP/2, and HTTP/3 differences.
Cloud Security: IAM, Network Isolation, and Encryption
Implement defense-in-depth security for cloud infrastructure—identity and access management, network isolation, encryption, and security monitoring.
Docker Networking: From Bridge to Overlay
Master Docker's networking models—bridge, host, overlay, and macvlan—for connecting containers across hosts and distributed applications.