Module 1 — Tổng kết & cheat sheet
Recap TCP/UDP deep dive: state machine đầy đủ, bảng so sánh TCP vs UDP, bảng tra lỗi mạng, glossary 20 thuật ngữ, pitfall tổng hợp và self-assessment.
TL;DR: Module 1 đào sâu tầng Transport — từ 3-way handshake đến TIME_WAIT, từ slow start đến PMTUD black-hole. Đây là một trang để bookmark: TCP state machine đầy đủ, bảng so sánh TCP vs UDP, bảng tra lỗi mạng (ECONNREFUSED/RESET/ETIMEDOUT), glossary 20 thuật ngữ và 5 pitfall lớn nhất. Nếu bạn giải thích được handshake, chẩn đoán được TIME_WAIT/CLOSE_WAIT và chọn đúng TCP vs UDP theo bài toán, bạn đã sẵn sàng cho Module 2 — HTTP & Web.
Đã đi qua những gì
Bạn bắt đầu từ bài 00 — Tổng quan module: tầng Transport không chỉ "gửi byte" — nó quyết định gửi như thế nào (tin cậy hay nhanh, có thứ tự hay không).
Bài 01 mổ xẻ 3-way handshake: ba gói SYN/SYN-ACK/ACK để đồng bộ ISN cho cả hai chiều full-duplex, tốn 1 RTT trước byte dữ liệu đầu tiên — động lực trực tiếp của keep-alive và connection pool.
Bài 02 đi vào TCP reliability: sequence number đánh dấu từng byte, ACK xác nhận đã nhận tới đâu, retransmission với exponential backoff khi mất gói. SACK giúp retransmit đúng mảnh thiếu thay vì retransmit toàn bộ.
Bài 03 giải thích flow control (rwnd — receiver nói "tôi chứa được bao nhiêu") và congestion control (cwnd — sender tự điều tiết theo tình trạng mạng): slow start, congestion avoidance, fast retransmit, CUBIC/BBR.
Bài 04 đào sâu TIME_WAIT và CLOSE_WAIT: tại sao kết nối đóng rồi vẫn chiếm port 2×MSL, CLOSE_WAIT sinh ra khi ứng dụng quên gọi close(), và hậu quả khi cạn ephemeral port ở tải cao.
Bài 05 so sánh TCP vs UDP: UDP không handshake, không retransmit, không thứ tự — đổi lại latency thấp và phù hợp với bài toán cần kiểm soát retransmit ở tầng ứng dụng (game, video, QUIC).
Bài 06 kết nối lý thuyết vào thực chiến: connection pool và HTTP keep-alive tái dùng kết nối để tránh trả handshake nhiều lần; TCP keep-alive phát hiện connection chết.
Bài 07 phân tích bốn lỗi mạng kinh điển: ECONNREFUSED (không ai listen, có RST ngay), ECONNRESET (kết nối bị phá giữa chừng), ETIMEDOUT (gói bị nuốt im lặng), EADDRINUSE (port bị chiếm). Mỗi lỗi chỉ về một chặng hỏng khác nhau.
Bài 08 giải thích tại sao ping được mà app timeout: MTU 1500 byte, fragmentation, PMTUD — và PMTUD black-hole khi firewall chặn ICMP "Fragmentation Needed" khiến gói lớn bị drop âm thầm.
🗺️ Cheat sheet
TCP state machine — toàn bộ vòng đời kết nối
stateDiagram-v2
[*] --> CLOSED
CLOSED --> LISTEN: passive open (server)
CLOSED --> SYN_SENT: active open / SYN
LISTEN --> SYN_RCVD: SYN / SYN-ACK
SYN_SENT --> ESTABLISHED: SYN-ACK / ACK
SYN_RCVD --> ESTABLISHED: ACK
ESTABLISHED --> FIN_WAIT_1: close / FIN (chu dong dong)
ESTABLISHED --> CLOSE_WAIT: FIN / ACK (thu dong)
CLOSE_WAIT --> LAST_ACK: close / FIN
FIN_WAIT_1 --> FIN_WAIT_2: ACK
FIN_WAIT_1 --> CLOSING: FIN / ACK
FIN_WAIT_2 --> TIME_WAIT: FIN / ACK
CLOSING --> TIME_WAIT: ACK
LAST_ACK --> CLOSED: ACK
TIME_WAIT --> CLOSED: 2xMSL timeoutĐọc state machine với ss:
# Xem tat ca ket noi voi state
ss -tan
# State Recv-Q Send-Q Local Address:Port Peer Address:Port
# LISTEN 0 128 0.0.0.0:8080
# ESTABLISHED 0 0 10.0.0.5:8080 10.0.0.1:54321
# TIME_WAIT 0 0 10.0.0.5:8080 10.0.0.1:54320
# CLOSE_WAIT 42 0 10.0.0.5:8080 10.0.0.1:54319
# Loc theo state
ss -tan state time-wait | wc -l # bao nhieu TIME_WAIT?
ss -tan state close-wait # ung dung quen close()?
So sánh TCP vs UDP
| Tiêu chí | TCP | UDP |
|---|---|---|
| Kết nối | Cần handshake (1 RTT) | Không cần |
| Tin cậy | Có (ACK + retransmit) | Không — ứng dụng tự xử lý |
| Thứ tự | Đảm bảo | Không đảm bảo |
| Flow control | Có (rwnd) | Không |
| Congestion control | Có (cwnd, slow start) | Không |
| Overhead header | 20 byte | 8 byte |
| Latency | Cao hơn (handshake + ACK) | Thấp hơn |
| Dùng cho | HTTP, database, file transfer, SSH | DNS, video stream, game, QUIC/HTTP3 |
| Retransmit | OS tự động | Ứng dụng tự quyết định |
Quy tắc chọn: dùng TCP khi mất một byte là không chấp nhận được. Dùng UDP khi gói cũ (stale) còn tệ hơn không có gói — như video call, game real-time, hoặc khi ứng dụng muốn kiểm soát hoàn toàn retransmit logic (QUIC).
Bảng tra lỗi mạng
| Lỗi | Tốc độ xuất hiện | Nguyên nhân phổ biến | Công cụ xác nhận |
|---|---|---|---|
ECONNREFUSED | Tức thì (dưới 1s) | Không có process LISTEN ở port | ss -tlnp, nc -zv |
ECONNRESET | Bất kỳ lúc | Server crash, LB idle timeout, pool connection chết | tcpdump xem RST, check LB log |
ETIMEDOUT | Sau 30-127s (SYN) | Firewall DROP, route hỏng, backlog đầy, PMTUD black-hole | tcpdump không thấy SYN-ACK |
EADDRINUSE | Khi bind port | TIME_WAIT hoặc process khác giữ port | ss -tlnp, lsof -i :<port> |
EPIPE | Khi write | Peer đã đóng socket phía nhận | Application log |
MTU & PMTUD cheat sheet
| Môi trường | MTU thường gặp | Ghi chú |
|---|---|---|
| Ethernet LAN | 1500 byte | Chuẩn IEEE 802.3 |
| WireGuard VPN | 1420 byte | Trừ 80 byte overhead |
| IPsec (ESP/UDP) | 1400-1450 byte | Tùy cipher suite |
| PPPoE (ADSL/FTTH) | 1492 byte | Trừ 8 byte PPPoE header |
| AWS EC2 (Nitro) | 9001 byte (jumbo) | Chỉ trong VPC, không ra Internet |
Test MTU: ping -M do -s 1472 <host> — nếu fail → MTU nhỏ hơn 1500.
Fix black-hole: iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
📖 Glossary module
| Thuật ngữ | Định nghĩa 1 câu |
|---|---|
| SYN | Cờ TCP "synchronize" — gói đầu tiên của handshake, mang ISN của sender. |
| ACK | Cờ TCP "acknowledge" — xác nhận đã nhận tới byte nào. |
| ISN | Initial Sequence Number — số thứ tự byte đầu tiên, chọn ngẫu nhiên để chống tấn công đoán số thứ tự. |
| RTT | Round-Trip Time — thời gian gói đi tới đích và nhận phản hồi về. |
| MSS | Maximum Segment Size — kích thước tối đa của phần dữ liệu trong một TCP segment (thường 1460 byte). |
| MTU | Maximum Transmission Unit — kích thước frame tối đa của một chặng mạng (Ethernet: 1500 byte). |
| cwnd | Congestion Window — giới hạn số byte sender gửi trước khi cần ACK, điều tiết theo tình trạng mạng. |
| rwnd | Receive Window — số byte receiver còn chứa được trong buffer, gửi về trong ACK để điều tiết sender. |
| Slow start | Pha đầu của TCP congestion control: cwnd tăng theo hàm mũ cho đến khi gặp ssthresh. |
| TIME_WAIT | Trạng thái sau khi chủ động đóng kết nối — giữ khoảng 2×MSL (60-120 giây) để đảm bảo ACK cuối không bị mất. |
| CLOSE_WAIT | Trạng thái khi nhận FIN từ peer nhưng ứng dụng chưa gọi close() — thường do bug ứng dụng. |
| Ephemeral port | Port tạm thời do OS cấp cho kết nối outbound client (thường 32768-60999 trên Linux). |
| Keep-alive | TCP keep-alive: probe định kỳ để phát hiện connection chết. HTTP keep-alive: tái dùng TCP connection cho nhiều HTTP request. |
| SACK | Selective ACK — cho phép receiver báo chính xác mảnh nào nhận được, giúp retransmit đúng mảnh thiếu thay vì toàn bộ. |
| PMTUD | Path MTU Discovery — cơ chế tìm MTU nhỏ nhất trên toàn tuyến đường, dùng cờ DF=1 và ICMP Fragmentation Needed. |
| PMTUD black-hole | Tình trạng PMTUD bị phá vỡ do firewall chặn ICMP type 3 code 4 — gói lớn bị drop âm thầm. |
| QUIC | Giao thức transport của Google (chuẩn hoá RFC 9000) — chạy trên UDP, tích hợp TLS, multiplexing không HOL blocking, thay TCP cho HTTP/3. |
| RST | Cờ TCP "reset" — buộc đóng kết nối ngay lập tức, không qua 4-way handshake. |
| Backlog | Hàng đợi kết nối SYN đang chờ accept() — giới hạn bởi tham số listen() và sysctl net.core.somaxconn. |
| Fragmentation | Phân mảnh gói IP thành nhiều mảnh nhỏ hơn MTU để qua được chặng mạng — reassembly ở đích. |
⚠️ Pitfall tổng hợp
Pitfall 1 — Nhầm ECONNREFUSED với bị firewall chặn.
ECONNREFUSED đến tức thì và có RST — nghĩa là gói đã đến được server OS, firewall không chặn. Vấn đề là không có process LISTEN ở port đó. Firewall chặn gây ETIMEDOUT (im lặng, chậm). Hai hướng debug hoàn toàn khác nhau.
Pitfall 2 — Connection pool không cấu hình keep-alive, giữ connection chết.
LB có idle timeout (thường 60-300s). Pool giữ connection lâu hơn timeout đó mà không kiểm tra → pool cho mượn connection đã bị LB close → ECONNRESET. Fix: maxLifetime của pool phải ngắn hơn LB idle timeout ít nhất 30 giây. HikariCP: keepaliveTime, Apache HttpClient: validateAfterInactivity.
Pitfall 3 — CLOSE_WAIT tích lũy do ứng dụng không gọi close().
Khi peer gửi FIN, ứng dụng nhận được sự kiện "đối tác đóng" nhưng quên gọi close() trên socket → kết nối kẹt ở CLOSE_WAIT mãi mãi. Mỗi kết nối CLOSE_WAIT chiếm file descriptor. Ứng dụng node/Java/Go không dùng try-with-resources hay bỏ sót error handler là nguyên nhân phổ biến. Dấu hiệu: ss -tan state close-wait | wc -l tăng dần.
Pitfall 4 — Ping thành công nhầm tưởng network ổn.
Ping dùng ICMP — không liên quan TCP. Firewall có thể allow ICMP nhưng DROP TCP port cụ thể. PMTUD black-hole cũng thế: ping (gói nhỏ) thông, TCP data lớn (TLS certificate, HTTP response) timeout. Test TCP thật bằng nc -zv host port hoặc curl -v. Test MTU bằng ping -M do -s 1472.
Pitfall 5 — TIME_WAIT gây EADDRINUSE khi restart server tải cao.
Server bị tải cao, xử lý nhiều kết nối ngắn → nhiều TIME_WAIT tích lũy → restart → bind() báo EADDRINUSE. Fix tức thì: SO_REUSEADDR trên server socket. Fix căn gốc: dùng connection pool để tái dùng kết nối, tránh open/close quá nhiều. Hiểu cơ chế: bài 04 giải thích tại sao TIME_WAIT phải kéo dài 2×MSL.
✅ Self-assessment
Bạn đã đạt module này nếu trả lời được:
- Explain được 3-way handshake và cách TCP đảm bảo dữ liệu đúng thứ tự — SYN/SYN-ACK/ACK đồng bộ ISN hai chiều, sequence number đánh dấu từng byte, ACK xác nhận, retransmit khi mất.
- Nếu chưa: đọc lại bài 01 (handshake, mục 2-3) và bài 02 (reliability, mục sequence + ACK).
- Diagnose được TIME_WAIT, CLOSE_WAIT và cạn ephemeral port — dùng
ss -tanđọc state, biết nguyên nhân và cách fix từng trường hợp.- Nếu chưa: đọc lại bài 04 (TIME_WAIT & CLOSE_WAIT), bài 07 (EADDRINUSE).
- Choose được giữa TCP và UDP theo bài toán — biết khi nào cần tin cậy (TCP), khi nào latency quan trọng hơn reliability (UDP/QUIC).
- Nếu chưa: đọc lại bài 05 (TCP vs UDP, mục "Khi nào dùng UDP").
🚀 What's next
Module 1 cho bạn hiểu tầng Transport — cái nền mọi ứng dụng web đều đặt lên đó. Module 2 — HTTP & Web phóng to tầng Application: HTTP/1.1 hoạt động thế nào (pipelining, HOL blocking), HTTP/2 giải quyết gì (multiplexing, header compression, server push), HTTP/3 trên QUIC tránh được gì. Hiểu Module 2, bạn đọc được Network tab của DevTools, biết vì sao request thứ 4 phải chờ request thứ 3, và chọn đúng HTTP version cho use case.
Bài tiếp theo: Module 2 — HTTP & Web: tổng quan
📚 Tài liệu mở rộng
- Sách: TCP/IP Illustrated, Vol. 1: The Protocols — W. Richard Stevens. Cuốn kinh điển nhất về TCP/IP, mổ xẻ từng packet với tcpdump thật. Chapters 17-24 bao gồm mọi concept trong module này.
- Sách: High Performance Browser Networking — Ilya Grigorik (O'Reilly, đọc miễn phí tại hpbn.co). Chapter 2 về TCP, chapter 4 về TLS, chapter 10-12 về HTTP/1-2-3. Góc nhìn performance thực tế, nhiều số liệu đo lường.
- RFC 9293 — Transmission Control Protocol (2022): bản hợp nhất mới nhất của TCP, thay thế RFC 793. Tra cứu khi cần câu trả lời chính thức về hành vi TCP.
- RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport: đặc tả QUIC — giao thức thay TCP cho HTTP/3. Đọc phần Introduction để hiểu motivation.
- Blog: Cloudflare Blog — "How to receive a million packets per second" và "We have seen things you people wouldn't believe — TCP over Satellite." Ví dụ thực tế về tuning TCP ở scale lớn.
Bài này đáng gửi cho bạn học cùng?
Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên