一句话总结:上网 = 先查地址(DNS),再修路(TCP 握手),最后送货(HTTP)。 适用:Linux 运维排错、面试常问的协议细节。
一、一次网页访问的完整流程
- 本机配好网络信息:IP 地址、子网掩码、网关、DNS;
- 访问
www.baidu.com; - DNS 解析出网站 IP(基于 UDP 53);
- HTTP 协议封装请求;
- TCP 协议封装(源端口、目标端口),三次握手建连接;
- IP 协议封装(源 IP、目标 IP);
- 以太网协议封装(源 MAC、目标 MAC,靠 ARP 得到);
- 数据变成电信号/光信号发出去,经过路由逐跳转发;
- 服务器回响应,浏览器渲染页面。
真正发 HTTP 之前,底层已经跑了 DNS、ARP、TCP 握手(HTTPS 还有 TLS 握手)好几趟。
二、DNS:把域名翻译成 IP
解析顺序
- 浏览器访问:浏览器缓存 → 本地 hosts 文件 → 系统 DNS 缓存 → 本地 DNS 服务器 → 根 DNS(13 组)→ 顶级域名服务器 → 二级/权威 DNS;
- 非浏览器(如 ping):本地 hosts 文件 → 系统 DNS 缓存 → 本地 DNS 服务器。
改 hosts 会影响系统 DNS 缓存。Windows 可用
ipconfig /displaydns查看缓存、ipconfig /flushdns清空;Linux 看nscd/systemd-resolved的状态。
递归查询 vs 迭代查询
| 方式 | 谁在干活 | 例子 |
|---|---|---|
| 递归 | 你只问一次,对方负责问到底并给你最终答案 | 本机 → 本地 DNS |
| 迭代 | 对方只告诉你“下一步去问谁”,你自己继续问 | 本地 DNS → 根/TLD/权威 |
本机 ──递归──> 本地 DNS ──迭代──> 根 ──> .com TLD ──> baidu.com 权威 ──> 返回 IP
常见记录类型
| 类型 | 作用 | 例子 |
|---|---|---|
| A | 域名 → IPv4 | www.example.com. A 1.2.3.4 |
| AAAA | 域名 → IPv6 | |
| CNAME | 别名指向另一个域名 | www → example.com |
| MX | 邮件服务器 | example.com. MX 10 mail |
| NS | 该域由哪台 DNS 负责 | |
| PTR | IP → 域名(反解) | |
| TXT | 文本,常用于校验、SPF |
dig www.baidu.com # 最常用
dig +short www.baidu.com # 只要结果
dig @8.8.8.8 example.com # 指定 DNS 服务器
nslookup baidu.com
cat /etc/resolv.conf # 看本机用的是哪个 DNS
三、TCP:可靠传输
TCP 靠确认机制(ACK)+ 序号 + 重传保证可靠,通信前必须建立双向通路。
三次握手
| 次数 | 方向 | 报文 | 状态变化 |
|---|---|---|---|
| 1 | Client → Server | SYN=1, seq=x |
Client:CLOSED → SYN_SENT |
| 2 | Server → Client | SYN=1, ACK=1, seq=y, ack=x+1 |
Server:LISTEN → SYN_RCVD |
| 3 | Client → Server | ACK=1, seq=x+1, ack=y+1 |
双方进入 ESTABLISHED |
为什么是三次,不是两次或四次?
- 不是两次:防止历史失效的 SYN 到达服务端,让服务端单方面建立无效连接、浪费资源;第三次 ACK 让服务端确认客户端确实收到了自己的 SYN,双方序列号同步。
- 不是四次:服务端可以把“对客户端 SYN 的 ACK”和“自己的 SYN”合并成
SYN+ACK,所以三次就够。
四次挥手
| 次数 | 方向 | 报文 | 状态变化 |
|---|---|---|---|
| 1 | 主动方 → 被动方 | FIN=1, seq=u |
主动:ESTABLISHED → FIN_WAIT_1 |
| 2 | 被动方 → 主动方 | ACK=1, ack=u+1 |
被动:→ CLOSE_WAIT;主动:→ FIN_WAIT_2 |
| 3 | 被动方 → 主动方 | FIN=1, seq=w, ack=u+1 |
被动:CLOSE_WAIT → LAST_ACK |
| 4 | 主动方 → 被动方 | ACK=1, ack=w+1 |
被动:→ CLOSED;主动:→ TIME_WAIT,等 2MSL 后 CLOSED |
为什么四次? TCP 是全双工,两个方向要分别关闭:主动方发 FIN 只关了自己这个方向,被动方可能还有数据要发,先回 ACK,等应用也 close() 后再发 FIN。
TIME_WAIT 为什么要等 2MSL?
- 保证最后一个 ACK 能到达(丢了对方会重发 FIN,还能回 ACK);
- 让本连接旧的重复报文在网络中消失,避免影响下一个同四元组的新连接。
服务器上大量
TIME_WAIT通常不是故障,是主动关闭连接太多;可调net.ipv4.tcp_tw_reuse等参数,但不要盲目调。
半连接队列与全连接队列
| 队列 | 存放什么 | 状态 |
|---|---|---|
| 半连接队列(SYN queue) | 收到 SYN、还没完成三次握手的连接 | SYN_RCVD |
| 全连接队列(accept queue) | 握手完成、等待应用 accept() 取走 |
ESTABLISHED |
队列大小受内核参数控制,不是越大越好,关键看服务端处理速度(出水口要大于进水口)。
SYN Flood 与 SYN Cookies
大量伪造源地址的客户端只发 SYN 就跑,服务端进入 SYN_RCVD 等待永远等不到的 ACK,半连接队列被占满,正常用户连不进来。
SYN Cookies:服务端收到 SYN 不立即分配状态,而是用源 IP、源端口、目的 IP、目的端口、时间戳和密钥算出一个 cookie,作为 SYN+ACK 的序列号;收到第三次 ACK 时用 ack-1 验证,合法才建立连接。这样未验证的连接不占队列。
四、TCP 与 UDP
| 对比 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 确认、重传、排序 | 不保证 |
| 速度/开销 | 慢、头大(20 字节起) | 快、头小(8 字节) |
| 传输方式 | 字节流 | 数据报 |
| 典型应用 | HTTP、SSH、MySQL | DNS、DHCP、视频、游戏 |
五、HTTP 与 HTTPS
- HTTP 是无状态的请求-响应协议:客户端发请求,服务端回响应;靠 Cookie/Session 维持状态。
- 常见方法:
GET(查)、POST(提交)、PUT(改)、DELETE(删)、HEAD(只要头)。 - 常见状态码:
| 状态码 | 含义 |
|---|---|
| 200 | 成功 |
| 301 / 302 | 永久 / 临时重定向 |
| 304 | 缓存未过期 |
| 400 | 请求有误 |
| 401 / 403 | 未认证 / 无权限 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
| 502 / 504 | 网关错误 / 网关超时 |
- HTTPS = HTTP + TLS:TCP 建连后先做 TLS 握手(证书校验、协商密钥),之后的数据对称加密传输。
curl -I https://www.baidu.com # 只看响应头
curl -v https://www.baidu.com # 看完整握手过程
六、排错命令
| 命令 | 用途 | 例子 |
|---|---|---|
ping |
测通断、看延迟 | ping -c 4 8.8.8.8 |
traceroute |
逐跳路径 | traceroute -n www.baidu.com |
ss -tunlp |
看端口和连接(推荐) | ss -tunlp \| grep 80 |
netstat -tunlp |
老命令,需装 net-tools | |
dig / nslookup |
DNS 排查 | dig +short baidu.com |
curl |
HTTP 调试 | curl -I http://127.0.0.1 |
tcpdump |
抓包 | tcpdump -i eth0 -nn port 80 -c 10 |
nc / telnet |
测端口通不通 | nc -zv 192.168.0.1 22 |
速查表
DNS:浏览器缓存 → hosts → 系统缓存 → 本地DNS → 根 → TLD → 权威
本机→本地DNS 递归;本地DNS→上层 迭代
TCP 三次握手:SYN → SYN+ACK → ACK
TCP 四次挥手:FIN → ACK → FIN → ACK,主动方 TIME_WAIT 2MSL
SYN Flood 防御:SYN Cookies + 调大队列 + 限速/防火墙
端口:22 SSH 53 DNS 80 HTTP 443 HTTPS 3306 MySQL 6379 Redis
| 状态 | 含义 |
|---|---|
| LISTEN | 服务端在监听 |
| SYN_SENT / SYN_RCVD | 握手中 |
| ESTABLISHED | 连接已建立 |
| FIN_WAIT_1/2 | 主动关闭方等待 |
| CLOSE_WAIT | 被动关闭方等待应用关闭 |
| TIME_WAIT | 主动关闭方等 2MSL |
常见坑
ping通不代表端口通,端口要用nc/telnet/ss验证。ping不通也可能是防火墙禁了 ICMP,不一定是断网。curl卡住多半是 DNS 慢或 TCP 连不上,先用-v看卡在哪一步。TIME_WAIT多不等于被攻击,先看是不是短连接太多。- 改完 DNS 配置要清缓存,否则验证的还是旧结果。
- 抓包要加
-nn不解析域名和端口名,否则又慢又乱。 - HTTPS 排错先看证书是否过期、域名是否匹配,再看握手。
练习(14 题)
- 写出浏览器访问网站时 DNS 的完整解析顺序。
- 递归查询和迭代查询的区别是什么?
- 本机访问
www.example.com,谁在做递归、谁在做迭代? - 简述 TCP 三次握手的报文和状态变化。
- 为什么 TCP 握手是三次而不是两次?
- 为什么挥手通常要四次?什么情况下看起来像三次?
- TIME_WAIT 状态要等多久?为什么必须等?
- 半连接队列和全连接队列分别存放什么状态的连接?
- SYN Flood 的原理是什么?SYN Cookies 怎么防?
- TCP 和 UDP 各举两个典型应用。
- 状态码 301、304、403、502 分别代表什么?
- HTTPS 相比 HTTP 多了什么过程?
- 服务器 80 端口疑似不通,用哪两条命令验证?
- 如何只抓 eth0 上 80 端口的前 10 个包?
答案与解析
1.
浏览器缓存 → 本地 hosts → 系统 DNS 缓存 → 本地 DNS 服务器 → 根 DNS → 顶级域名服务器 → 二级/权威 DNS。
2.
递归是“你只问一次,对方负责问到底并给最终结果”;迭代是“对方只告诉你下一步问谁”,由你自己继续问。
3.
本机对本地 DNS 是递归(本地 DNS 负责查到最终 IP);本地 DNS 对根/TLD/权威服务器是迭代(逐级去问)。
4.
客户端发
SYN=1, seq=x,进入 SYN_SENT;服务端回SYN=1, ACK=1, seq=y, ack=x+1,进入 SYN_RCVD;客户端回ACK=1, ack=y+1,双方进入 ESTABLISHED。
5.
防止历史失效的 SYN 让服务端建立无效连接;第三次 ACK 让服务端确认客户端收到了自己的 SYN,双方序列号同步。
6.
因为 TCP 全双工,两个方向要分别关闭;如果被动方也没有数据要发,ACK 和 FIN 可以合并发送,抓包看起来像三次。
7.
等 2MSL(报文最大生存时间的两倍)。一是保证最后的 ACK 能到达(丢了对方会重发 FIN),二是让旧连接的重复报文消失,避免影响新连接。
8.
半连接队列放收到 SYN、还没完成握手的连接(SYN_RCVD);全连接队列放握手完成、等待应用 accept 的连接(ESTABLISHED)。
9.
攻击者伪造大量源地址只发 SYN 不完成握手,把半连接队列占满。SYN Cookies 不保存未验证连接的状态,而是用五元组+时间+密钥算出 cookie 当序列号,收到 ACK 时验证,合法才建连接。
10.
TCP:HTTP、SSH、MySQL;UDP:DNS、DHCP、视频直播、在线游戏。
11.
301 永久重定向;304 缓存未过期(用本地缓存);403 禁止访问(无权限);502 网关收到上游错误响应。
12.
多了 TLS 握手:证书校验、密钥协商,之后数据对称加密传输。
13.
ss -tunlp | grep ':80'
nc -zv 192.168.0.163 80
前者看本机是否有服务监听,后者从客户端测端口连通性。
14.
tcpdump -i eth0 -nn port 80 -c 10