Appearance
网络基础
Linux 网络排错,绕不开几个核心概念:IP 地址、子网掩码、网关、DNS、端口、TCP 连接。后面所有的网络配置和诊断命令,都是基于这几个概念展开的。这套基础打牢了,排查网络问题的时候才知道每一步在查什么、为什么这么查——不然就是按教程敲命令,看到输出也不知道该怎么读。
一、IP 地址
IP 地址是主机在网络里的身份标识。Linux 上一张网卡可以绑一个或多个 IP,服务监听的时候可以选择只监听某个特定 IP,也可以监听所有地址——这个选择直接影响外部能不能访问,后面会专门讲。
IPv4 地址是 32 位的,平时写成点分十进制,比如 192.168.1.10。按使用范围分公网地址和私有地址,私有地址只能在局域网或内网里用,不能直接在公网上路由。三个私有地址网段记一下:10.0.0.0/8、172.16.0.0/12、192.168.0.0/16——服务器内网通信基本都在这些网段里。
几个特殊地址要记住:127.0.0.1 是本机回环地址(localhost),只能本机访问自己;0.0.0.0 在服务监听时表示"本机所有 IPv4 地址";::1 是 IPv6 的回环地址。
有个特别常见的坑:服务只监听了 127.0.0.1:8080,本机 curl 127.0.0.1:8080 没问题,但外部机器死活连不上——哪怕防火墙全开了也不行,因为服务根本不接收来自其他 IP 的连接。排查"服务起来了但外部访问不了"这种问题,第一眼就看监听地址是不是 127.0.0.1,十有八九是这个原因。
二、子网掩码和 CIDR
子网掩码用来区分 IP 地址里哪部分是"网络"、哪部分是"主机"。同一个网段内的机器,网络部分相同,可以直接通信;不同网段的,得经过网关转发。这个概念理解了,后面的路由就好懂了。
CIDR(无类别域间路由)写法把掩码长度直接写在 IP 后面,比如 192.168.1.10/24——/24 表示前 24 位是网络位,剩下 8 位是主机位。192.168.1.10/24 所在的网段:网络地址是 192.168.1.0,可用主机范围 192.168.1.1 到 192.168.1.254,广播地址 192.168.1.255(网络地址和广播地址不能分配给主机)。
常见 CIDR 对照,背一下常用的:
| CIDR | 子网掩码 | 可用主机数 |
|---|---|---|
/24 | 255.255.255.0 | 254 |
/25 | 255.255.255.128 | 126 |
/26 | 255.255.255.192 | 62 |
/16 | 255.255.0.0 | 65534 |
一个容易搞错的点:两台机器是不是同一网段,不是看 IP 地址像不像,而是看 IP + 掩码一起算出来的网络地址一不一样。比如 192.168.1.200/24 属于 192.168.1.0/24 网段,但 192.168.1.200/25 属于 192.168.1.128/25 网段——同一个 IP,掩码不同,归属的网段完全不同。云主机上改网卡配置时掩码填错,就会出现"IP 看着是对的,但就是不通"这种诡异现象。
三、网关
默认网关是内网主机通往外部网络的出口。访问不在本网段的地址时,数据包就发给默认网关,由网关负责往下一跳转发。
bash
ip route输出大概长这样:
default via 192.168.1.1 dev eth0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10第一行 default via 192.168.1.1 dev eth0:所有目的地不在路由表里的流量(default),都从 eth0 发给下一跳 192.168.1.1(这就是网关)。第二行是直连网段:192.168.1.0/24 这个网段的流量直接从 eth0 出去,源地址是 192.168.1.10。
路由匹配遵循**"最长前缀优先"原则**——去往 10.10.1.2 的包,如果路由表里同时有 10.0.0.0/8 和 10.10.0.0/16,会匹配更具体的 /16(掩码更长 = 更精确)。理解这个原则,排查"流量走了错误的下一跳"这类问题就有方向了。
四、DNS
DNS 把人类好记的域名翻译成机器要用的 IP 地址。
bash
cat /etc/resolv.conf # 查看当前用的 DNS 服务器Linux 的域名解析顺序由 /etc/nsswitch.conf 里的 hosts 行控制:
bash
grep '^hosts:' /etc/nsswitch.conf输出 hosts: files dns 表示先查 /etc/hosts 文件,再查 DNS。线上经常踩一个坑:DNS 明明改了,机器还解析到旧 IP,最后发现是 /etc/hosts 里写死了一个旧地址——因为 hosts 优先级在 DNS 前面,改了 DNS 没用。所以排查域名解析异常,/etc/hosts 和 nsswitch.conf 要一起看。
解析域名,几个命令各有侧重:
bash
getent hosts example.com # 走系统 NSS,模拟应用真实的解析路径
dig example.com # 直接查 DNS,绕过 hosts 和本地缓存
dig @8.8.8.8 example.com # 指定用某个 DNS 服务器查排查"应用解析到的 IP 跟预期不一样"的时候,用 getent hosts——它的解析路径跟应用一致(包括 hosts、DNS、LDAP 这些,看 nsswitch 配置)。而 dig 是直接查 DNS 的,绕过 hosts 文件,适合确认"DNS 本身返回的是什么"。
五、端口
端口是传输层(TCP/UDP)用来区分同一台机器上不同服务的编号。同一个 IP 上可以同时跑 HTTP(80)、SSH(22)、MySQL(3306),就靠端口号区分。
端口范围分几段:0-1023 是知名端口(Well-known),绑定需要 root 权限;1024-49151 是注册端口;49152-65535 是临时/私有端口,客户端发起连接时通常从这个范围随机选一个。几个常见服务端口记一下:22 是 SSH、80 是 HTTP、443 是 HTTPS、3306 是 MySQL、6379 是 Redis、5432 是 PostgreSQL。
"端口通不通"其实要分好几个层面判断,不是一个命令能搞定的:本机服务有没有监听、本机防火墙放行了没、云安全组放行了没、中间网络路由可达吗、对端防火墙拦了没。排查时分层查——ss 看本机监听情况,telnet 或 nc 从远端测试连通性。
监听地址和端口的组合决定了可访问范围,这点跟前面 IP 那节呼应:
| 监听方式 | 谁能访问 |
|---|---|
127.0.0.1:8080 | 仅本机 |
0.0.0.0:8080 | 所有网卡、所有 IP 都能访问 |
192.168.1.10:8080 | 只能通过 192.168.1.10 这个 IP 访问 |
ss -lntp 输出里看到 127.0.0.1:8080,问题通常不在防火墙,而是服务配置本身就限制了只接收本机连接——得改服务配置,不是开防火墙能解决的。
六、OSI 模型与排障顺序
OSI 七层模型教科书里要背,但实际排障不需要严格背诵。更有用的是按层次从下往上排查的思路:
| 排查步骤 | 确认什么 | 用什么命令 |
|---|---|---|
| 1 | 网卡在不在、有没有 IP | ip addr |
| 2 | 路由正不正常 | ip route |
| 3 | DNS 能不能解析 | getent hosts <domain> |
| 4 | 本机端口监听了没 | ss -lntp |
| 5 | TCP 能不能连通 | curl -v、nc -zv |
| 6 | 应用有没有正常响应 | 看应用日志和返回内容 |
这个从下往上的顺序,通常比一上来就抓包更快定位问题。底层断了上层肯定不通,先确认底层没问题再往上查,效率最高。
七、TCP 三次握手
TCP 传输数据之前要先建立连接,这个过程叫三次握手。它本质上是双方互相确认"我能发、你能收"的过程,三步走:
| 步骤 | 方向 | 标志 | 在说什么 |
|---|---|---|---|
| 1 | 客户端 → 服务端 | SYN | "我想和你建立连接" |
| 2 | 服务端 → 客户端 | SYN-ACK | "收到,我也准备好了" |
| 3 | 客户端 → 服务端 | ACK | "收到你的确认,开始传数据" |
理解三次握手,就能解释两种常见的连接失败现象。如果服务端端口没监听,客户端发 SYN 后服务端会回 RST(复位),客户端立刻收到 Connection refused——说明包到了目标机器,只是端口没服务。如果中间网络或防火墙把 SYN 包丢了,客户端持续重发 SYN 但收不到任何回应,最终 Connection timed out——说明网络层面就不通。
bash
curl -v http://10.0.0.1:80/Connection refused 和 Connection timed out 是两个方向完全不同的信号,排查时一定要分清:前者是"到了对方但被拒",问题在服务端(端口没监听);后者是"根本到不了对方",问题在网络路径(路由、防火墙、对方机器不在线)。很多人把这两个混为一谈,排查方向就走错了。
UDP 没有三次握手,所以判断"UDP 端口通不通"没有 TCP 那么直观——发出去不知道对方收没收到。DNS(53/UDP)、NTP 这类 UDP 服务排查时,得看应用层有没有给出响应,或者直接抓包看 UDP 包有没有返回。