大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
网络基础
这一课你将能做到
- 查看本机 IP、路由、DNS 配置,说清一个请求从服务器发出到外网的完整路径
- 用 ss/netstat 查看端口监听状态,10 秒内回答「8080 端口是谁在监听」
- 用 ping、curl、dig、tcpdump 分层排查网络问题:是服务没起、防火墙拦了、还是 DNS 挂了
为什么要学
后端开发的本质是网络编程。本站架构里,浏览器 → Nginx(80/443)→ Spring Boot(8080)→ MySQL(3306)/ Redis(6379),每一跳都是 TCP 连接。线上「接口不通」的报警背后,可能是进程没监听端口、防火墙没放行、安全组没配置、DNS 解析错了 IP。不会网络排查,你连「问题出在哪一层」都说不清。
面试中「TCP 三次握手」「如何查看端口占用」「ping 通但 curl 不通是什么原因」是网络题的高频三件套。
先建立图像
本站请求链路(一次 API 调用的旅程):
浏览器
│ ① DNS 解析 codeforge.example.com → 服务器公网 IP
│ ② TCP 三次握手 → 443 端口
▼
Nginx(监听 443,终止 TLS)
│ ③ 反向代理:转发到 127.0.0.1:8080
▼
Spring Boot(监听 8080)
│ ④ JDBC 连接 MySQL(3306)、Lettuce 连接 Redis(6379)
▼
MySQL / Redis
网络排查的金字塔(从下到上逐层验证):
第 1 层:网卡有 IP 吗? ip addr
第 2 层:能出去吗? ping 网关 → ping 8.8.8.8
第 3 层:DNS 正常吗? dig baidu.com
第 4 层:目标端口通吗? curl -v / ss -tlnp
跟着做
步骤 1:查看本机网络配置
# 网卡与 IP(ip 是现代命令,ifconfig 已淘汰)
ip addr
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP>
# inet 10.0.12.5/24 ... ← 内网 IP,/24 是子网掩码
ip route # 路由表:default via 10.0.12.1 是默认网关
ip link # 网卡链路状态(UP/DOWN)
# DNS 配置
cat /etc/resolv.conf
resolvectl status 2>/dev/null | head # Ubuntu 18.04+ 的 systemd-resolved
步骤 2:端口查看——ss 是核心武器
# 查看所有 TCP 监听端口(排查「服务起没起」第一命令)
sudo ss -tlnp
# State Recv-Q Send-Q Local Address:Port Process
# LISTEN 0 511 0.0.0.0:80 users:(("nginx",pid=1000))
# LISTEN 0 128 0.0.0.0:3306 users:(("mysqld",pid=1200))
# LISTEN 0 100 127.0.0.1:6379 users:(("redis-server",pid=1300))
# LISTEN 0 100 127.0.0.1:8080 users:(("java",pid=1400))
# 参数记忆:t=tcp l=listen n=数字端口(不解析服务名) p=显示进程
# 谁占用了 8080?(端口冲突排查)
sudo ss -tlnp | grep 8080
sudo lsof -i :8080
# 看所有 ESTABLISHED 连接(当前有哪些活跃连接)
ss -tn state established
# 统计各状态连接数(排查 TIME_WAIT 堆积)
ss -tan | awk '{print $1}' | sort | uniq -c
关键细节:Redis 监听 127.0.0.1:6379 意味着只接受本机连接——外网连不上是设计如此(安全),不是故障。想让 Spring Boot 容器连另一台机器的 MySQL,MySQL 必须监听 0.0.0.0 或具体网卡 IP。
步骤 3:连通性测试三件套
# ping:测网络层连通性(ICMP 协议)
ping -c 4 8.8.8.8 # 通 = 网络层 OK
ping -c 4 baidu.com # 通 = DNS + 网络层都 OK
# ping 不通 IP → 网络断;ping 通 IP 但不通域名 → DNS 问题
# curl:测应用层(HTTP)——后端工程师的主力
curl -v http://localhost:8080/api/health # -v 看握手细节
curl -I https://codeforge.example.com # 只看响应头
curl -w "\n总耗时: %{time_total}s\n" -o /dev/null -s https://baidu.com # 测延迟
# telnet/nc:测传输层端口通不通(TCP 握手能不能完成)
sudo apt install -y netcat
nc -zv 127.0.0.1 3306 # 测 MySQL 端口
nc -zv 10.0.12.6 6379 # 测另一台服务器的 Redis
分层排查逻辑(面试标准答案):
nc 端口不通 → 服务没监听 / 防火墙拦了
nc 通但 curl 报错 → 应用层问题(TLS 证书、协议不对、后端 500)
ping 不通但 nc 通 → 对方禁 ping(ICMP),不是故障!
步骤 4:DNS 排查
sudo apt install -y dnsutils
dig baidu.com # 完整解析过程
dig +short baidu.com # 只要 IP
dig @223.5.5.5 baidu.com # 指定用阿里 DNS 解析(对比运营商 DNS 是否劫持)
nslookup baidu.com
# DNS 解析顺序(hosts 优先)
cat /etc/hosts
# 开发技巧:测试环境绑定域名
echo "10.0.12.5 test.codeforge.local" | sudo tee -a /etc/hosts
步骤 5:防火墙——ufw 与端口放行
# ufw 是 Ubuntu 的防火墙前端
sudo ufw status verbose
# 标准放行流程(本站上线时做过的事)
sudo ufw allow 22/tcp # SSH(必须先放行,否则把自己锁外面!)
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
sudo ufw status numbered # 带编号查看,方便删规则
# 只允许内网访问 MySQL(最小暴露原则)
sudo ufw allow from 10.0.12.0/24 to any port 3306
# 删除规则
sudo ufw delete allow 80/tcp
注意:云服务器还有一层「安全组」(控制台配置),ufw 和安全组是串联的两道门,只开一道还是不通。
步骤 6:tcpdump 抓包——终极武器
sudo apt install -y tcpdump
# 抓 8080 端口的包(看请求到底到没到服务器)
sudo tcpdump -i any port 8080 -nn
# 抓 MySQL 连接(排查连接超时)
sudo tcpdump -i any port 3306 -nn -c 20
# 保存到文件,用 Wireshark 图形化分析
sudo tcpdump -i any port 443 -w /tmp/https.pcap -c 100
# 看 TCP 握手标志(S=SYN, .=ACK, F=FIN, R=RST)
sudo tcpdump -i any 'tcp[tcpflags] & tcp-syn != 0' -nn # 只看 SYN 包,谁在连我
典型应用:客户端报「连接超时」,服务端 tcpdump port 8080 一个 SYN 包都没看到 → 请求根本没到服务器,问题在中间链路(安全组/防火墙/网络);能看到 SYN 但没回 SYN-ACK → 本机防火墙拦了。
步骤 7:路由追踪与综合演练
sudo apt install -y traceroute
traceroute -T -p 443 baidu.com # TCP 模式追踪(默认 UDP 常被运营商拦)
mtr baidu.com # ping + traceroute 合体,持续观测丢包(需安装)
# 演练:本站接口突然打不开了
# 1. 本机自测
curl -v http://localhost:8080/api/health # 通 → 应用 OK
# 2. 看 Nginx
sudo ss -tlnp | grep -E ':80|:443' # 在听 → Nginx OK
# 3. 看防火墙
sudo ufw status # 443 已放行 → OK
# 4. 抓包验证流量到没到
sudo tcpdump -i any port 443 -nn -c 5 # 无包 → 查云安全组!
# 结论:安全组里 443 规则被误删 → 控制台补回 → 恢复
讲清楚要点
- 监听地址决定谁能连:
127.0.0.1:8080只接受本机;0.0.0.0:8080接受所有网卡;内网IP:3306只接受内网。服务「起来了但外网连不上」,第一查 ss 里的监听地址。 - ss 取代 netstat:ss 更快(直接读内核 socket 表)。记
ss -tlnp(看监听)和ss -tan(看全部)两条就够日常用。 - ping 不通 ≠ 服务挂:ping 走 ICMP,很多服务器/防火墙禁 ping。测服务用
nc -zv或curl,别只会 ping。 - 防火墙是双层的:云安全组(控制台)+ 系统防火墙(ufw/iptables),任何一层拦了都不通。排障时两层都要查。
- TIME_WAIT 是正常状态:主动关闭连接的一端会进入 TIME_WAIT 保留 60 秒。高并发短连接会堆积大量 TIME_WAIT,通常是正常的;真正危险的是大量 CLOSE_WAIT(应用没关连接,代码 bug)。
- DNS 解析顺序:
/etc/hosts→ 系统 DNS(resolv.conf)→ 递归查询。hosts 文件优先,常被用于测试绑定和恶意劫持。 - tcpdump 是证据之王:「包到没到服务器」这种问题,猜一万次不如抓包看一次。
你可能会懵的地方
-
ss 里的 0.0.0.0 和 [::] 是什么? 0.0.0.0 表示监听所有 IPv4 网卡;[::] 表示监听所有 IPv6(通常也兼容 IPv4)。看到只监听 127.0.0.1 而你想外网访问,就要改应用配置。
-
curl 报
Connection refused和Connection timed out区别? refused:包到了,但没有进程监听该端口(或 REJECT 规则),对方明确拒绝。timed out:包发出去了石沉大海,通常是防火墙 DROP 或网络不通。refused 查服务,timeout 查防火墙。 -
为什么要有 TIME_WAIT?不能立即释放吗? TCP 协议设计要求:确保最后一个 ACK 能重传,以及让网络中游荡的旧包自然消亡,防止污染新连接。60 秒(2MSL)是协议规定的。
-
/etc/resolv.conf 改了重启又复原? Ubuntu 18.04+ 由 systemd-resolved 管理,resolv.conf 是指向它的符号链接。改 DNS 要用 netplan 配置或
resolvectl。 -
localhost、127.0.0.1、0.0.0.0 三个地址有什么区别? localhost 是域名(解析到 127.0.0.1);127.0.0.1 是回环 IP(流量不出本机);0.0.0.0 在监听语境下表示「所有网卡」,在路由语境下表示「默认路由」。绑定 0.0.0.0 的服务才能被外部访问。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 服务不通就重启应用 | 可能是防火墙/安全组,重启白费 | 分层排查:ss → curl 本机 → ufw → tcpdump |
| ping 不通就判定网络故障 | 对方可能禁 ping | 用 nc -zv IP 端口 测 TCP |
| MySQL 改 bind-address 后还是不连 | 只改配置没放开防火墙 | 配置 + ufw + 安全组三处一起检查 |
ufw enable 前没放行 22 | 把自己 SSH 锁在门外(真实事故高发) | 先 ufw allow 22/tcp 再 enable |
| 用 netstat 慢还缺信息 | 老命令,大连接表时卡 | 用 ss -tlnp |
| 只看 LISTEN 不看连接状态 | CLOSE_WAIT 堆积拖垮应用 | ss -tan state close-wait | wc -l 定期巡检 |
卡点急救
-
现象:本地 curl 通,外网 curl 超时 经典三层排查:
ss -tlnp看监听地址是不是 127.0.0.1(是则改配置绑 0.0.0.0)→ufw status看端口放没放 → 云控制台安全组。90% 的问题在这三处。 -
现象:Spring Boot 连 MySQL 报
Communications link failurenc -zv mysql-host 3306测连通性 → 通则查账号权限(MySQL 用户 host 限制'user'@'localhost'不接受远程)→ 不通查 mysqld 的 bind-address 和防火墙。 -
现象:接口间歇性超时,时好时坏 用
mtr 目标IP持续观测哪一跳丢包;服务器上ss -s看 socket 统计是否触顶;dmesg | tail看内核有没有丢包记录(conntrack 表满)。
面试常问
-
如何查看某个端口被哪个进程占用?
sudo ss -tlnp | grep :8080或sudo lsof -i :8080。杀死占用者:sudo kill PID。追问:ss 参数含义(t=tcp, l=listen, n=数字, p=进程)。 -
ping 能通但 telnet/curl 端口不通,可能原因? ping 走 ICMP 只证明网络层通。端口不通的可能:服务没监听该端口;服务只绑了 127.0.0.1;防火墙(iptables/ufw)拦截;云安全组未放行。分层验证:对端机器
ss -tlnp→curl localhost→ 本机nc -zv。 -
简述 TCP 三次握手,以及如何用工具观察到它? SYN → SYN+ACK → ACK。客户端发 SYN(我要连你),服务端回 SYN+ACK(可以,我也要连你),客户端回 ACK(好的,开始传数据)。观察:
tcpdump port 8080输出中[S]、[S.]、[.]三个包就是一次握手。握手失败(只看到 SYN 重传)说明对端没监听或被防火墙 DROP。
自测三问
ss -tlnp输出中 Redis 监听在127.0.0.1:6379,另一台服务器的应用能连上吗?为什么?- 浏览器访问本站超时,按什么顺序排查(至少 4 步)?
Connection refused和Connection timed out分别指向什么问题?
小结一句话
网络排查就一句话——分层验证:IP 层 ping、传输层 nc、应用层 curl、证据层 tcpdump;监听地址、防火墙、安全组是三个最经典的坑。
延伸
- Linux ip/ss 命令手册
- tcpdump 官方文档
- 下一课:SSH 与日志——安全登录、密钥认证、远程传文件与 auth 日志审计。