网络-05 网关、路由与 NAT
前置阅读:网络-03 IP 协议
上一篇讲了同一子网内怎么判断"我们是不是一家人"(IP 与子网掩码做与运算)。这一篇解决剩下的问题:不在同一个子网,数据怎么出去。
1. 网关
上面讲到只有在同一个网络才能进行通信,利用的是子网掩码。那就是需要不在同一个网络的计算器进行互连可怎么办?网关的作用就来了。
1.1 那么网关到底是什么呢?
网关实质上是一个网络通向其他网络的IP地址。比如有网络A和网络B,网络A的IP地址范围为“192.168.1.1~192. 168.1.254”,子网掩码为255.255.255.0;网络B的IP地址范围为“192.168.2.1~192.168.2.254”,子网掩码为255.255.255.0。在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不同的网络里。而要实现这两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目的主机不在本地网络中,就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机。网络B向网络A转发数据包的过程也是如此。所以说,只有设置好网关的IP地址,TCP/IP协议才能实现不同网络之间的相互通信。那么这个IP地址是哪台机器的IP地址呢?网关的IP地址是具有路由功能的设备的IP地址,具有路由功能的设备有路由器、启用了路由协议的服务器(实质上相当于一台路由器)、代理服务器(也相当于一台路由器)。 简单来说,tcp/ip发现两台计算机不在同一个网络,别怕,先发给自己所在网络的网关,利用网关传到另一网络中去,进而传到目标主机。
一台主机可以有多个网关,还会有一个默认网关,当不知道利用那个网关传数据的时候就用这个默认网关。
1.2 设置默认网关
设置默认网关可以手动和自动设置
- 手动设置不利于迁移,因为迁移时ip地址会改变
- 自动设置就是利用DHCP服务器来自动给网络中的电脑分配IP地址、子网掩码和默认网关。这样做的好处是一旦网络的默认网关发生了变化时,只要更改了DHCP服务器中默认网关的设置,那么网络中所有的电脑均获得了新的默认网关的IP地址。
2. 网关的 MAC 地址:一个关键细节
这里有个很多人忽略但极其重要的点:跨网段通信时,数据帧的目的 MAC 填的是网关的 MAC,而不是目标主机的 MAC。
回顾 网络-02 里的 ARP:ARP 只能在同一广播域内工作,你根本无法通过 ARP 拿到另一个网段主机的 MAC 地址。所以主机 A 给另一个网段的 B 发包时,流程是:
- A 用子网掩码算出「B 和我不在同一网段」;
- A 对默认网关的 IP 发 ARP,拿到网关的 MAC;
- A 构造数据包:IP 首部的目的 IP 写 B 的 IP(端到端不变),帧首部的目的 MAC 写网关的 MAC;
- 网关(路由器)收到帧,拆掉帧首部,查路由表决定下一跳,换上新的帧首部(目的 MAC 改为下一跳的 MAC)再发出去;
- 如此逐跳转发,每一跳都重写 MAC,直到最后一跳路由器发现目标就在自己直连的网段里,才 ARP 出 B 的真实 MAC 并投递。
一句话总结:IP 地址负责端到端寻址(全程不变),MAC 地址负责逐跳转发(每跳重写)。 这是理解整个转发链路最核心的一句话,也是面试高频考点。
3. 路由
路由器的核心工作是查路由表,决定数据包的下一跳去哪里。
静态路由:管理员手工配置路由表,指明"要到某个网段,下一跳走哪个路由器"。简单、可控、无额外开销,但网段一多就难以维护,而且网络拓扑变化时不会自动跟着变。
动态路由:路由器之间交换信息,自己学习和更新路由表,拓扑变化时能自动收敛。常见协议:
| 协议 | 类型 | 度量依据 | 适用范围 |
|---|---|---|---|
| RIP | 距离矢量 | 跳数(最多 15 跳) | 小型网络,基本已淘汰 |
| OSPF | 链路状态 | 链路开销(带宽等) | 企业/园区内部,最常用 |
| BGP | 路径矢量 | 策略(AS 路径等) | 互联网骨干、AS 之间 |
值得一提的是 BGP 是整个互联网的粘合剂——运营商之间靠它交换"我能到达哪些网段"。它基于策略而非单纯的最短路径,也因此几次著名的大范围断网事故都源于 BGP 配置错误(错误宣告了不属于自己的网段,把全球流量吸引过去)。
查看本机路由表:
route -n get default # macOS
ip route # Linux
netstat -rn # 通用
3.1 最长前缀匹配
路由表里可能有多条规则同时匹配一个目的地址,路由器选择前缀最长、范围最精确的那一条,而不是简单选择第一条:
10.0.0.0/8 via 192.168.1.1
10.10.0.0/16 via 192.168.1.2
10.10.20.0/24 via 192.168.1.3
0.0.0.0/0 via 192.168.1.254
访问 10.10.20.8 时三条 10.* 路由都能匹配,但 /24 最精确,所以走 192.168.1.3。只有没有更具体路由时才走 0.0.0.0/0 默认路由。若前缀长度相同,再比较 metric 等属性。
Linux 可直接让内核回答实际选择:
ip route get 10.10.20.8
ip -6 route get 2001:db8::10
这比盯着整张路由表人工推断更可靠。容器或 Pod 有独立网络命名空间时,必须进入对应 netns 查看,宿主机的路由表不等于容器里的路由表。
4. 私有地址
绝大部分计算机都是在一个内网中,而不是直接分配一个公网ipv4地址,我们可以用ipconfig查看一下本地的吧ip地址,然后对比一下公网ip地址:
ipconfig查出来的是你本机的IP地址,也就是内网私有地址,此类地址仅在局域网使用,不能联通外网。百度在线查出来的地址是你上网的公网地址。

5. NAT技术
公有IP地址有限,私有IP地址网络又不认识,私有地址怎么和公有地址电脑传数据呢?
net address translation技术解决,主要原理是就是在经过路由器时把目的IP或源IP,目的端口或源端口修改下。这里有一个地址和端口的转换表。

5.1 SNAT、DNAT 与 NAPT
| 类型 | 改写内容 | 常见场景 |
|---|---|---|
| SNAT | 改写源 IP | 内网主机访问公网 |
| DNAT | 改写目的 IP | 公网入口、端口映射、负载均衡 |
| NAPT/PAT | 同时改写 IP 和端口 | 多台内网主机共享一个公网 IP |
家庭路由器常见的是 NAPT。假设两台内网机器都从本地端口 50000 访问同一个网站,NAT 网关可能转换成:
10.0.0.10:50000 → 203.0.113.8:40001
10.0.0.11:50000 → 203.0.113.8:40002
公网回包到不同端口后,网关查转换表,再恢复成对应的内网地址。外部主机若没有既存表项或端口映射,就无法主动连接内网主机——NAT 破坏了 IP 原本的端到端连通性。
5.2 conntrack:NAT 为什么是有状态的
Linux 的 Netfilter 使用 conntrack 跟踪连接。它按五元组(协议、源/目的 IP、源/目的端口)记录连接状态,NAT 映射、状态防火墙和很多 Kubernetes Service 实现都依赖这张表。
conntrack -S
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
conntrack 表满时,新连接可能直接被丢弃,内核日志常出现:
nf_conntrack: table full, dropping packet
这类故障的典型表现是“已有长连接正常、新连接间歇超时”。只看应用日志和 ss 很容易漏掉,应该同时检查 dmesg、conntrack 使用率和 NAT 网关指标。
表项还有空闲超时。长连接如果长期没有数据,NAT/LB 可能先删除映射,而两端 socket 仍显示 ESTABLISHED。所以 WebSocket、gRPC stream 等长连接需要应用层心跳,且心跳间隔必须小于链路中最短的空闲超时。
5.3 NAT 端口耗尽
一个公网 IP 可用的源端口数量有限;同一目的地址下,一条 TCP 连接必须有唯一四元组。大量短连接经过同一个 NAT 出口时,可能耗尽可用映射端口。
Go 服务高并发调用下游时,最有效的解决方案不是盲目扩大端口范围,而是:
- 复用同一个
http.Transport; - 正确配置
MaxIdleConns、MaxIdleConnsPerHost; - 读取并关闭响应体,让连接能够回到连接池;
- 控制并发,必要时增加 NAT 出口 IP。
因此看到 cannot assign requested address、大量 TIME_WAIT 或“只有新建连接失败”时,要把本机临时端口和 NAT 端口同时纳入排查。
6. 总结:
网络通信就好比送快递,商品外面的一层层包裹就是各种协议,协议包含了商品信息、收货地址、收件人、联系方式等,然后还需要配送车、配送站、快递员,商品才能最终到达用户手中。
一般情况下,快递是不能直达的,需要先转发到对应的配送站,然后由配送站再进行派件。
配送车就是物理介质,配送站就是网关, 快递员就是路由器,收货地址就是IP地址,联系方式就是MAC地址。
快递员负责把包裹转发到各个配送站,配送站根据收获地址里的省市区,确认是否需要继续转发到其他配送站,当包裹到达了目标配送站以后,配送站再根据联系方式找到收件人进行派件。
7. 本章面试题
跨网段通信时,数据帧的目的 MAC 填的是谁的?(高频)
填的是网关(路由器)的 MAC,不是目标主机的 MAC。
原因:ARP 只能在同一广播域内工作,你根本无法通过 ARP 拿到另一个网段主机的 MAC。
完整流程:
- 用子网掩码算出目标不在同一网段;
- 对默认网关的 IP 发 ARP,拿到网关的 MAC;
- 构造包:IP 首部的目的 IP 写最终目标,帧首部的目的 MAC 写网关的 MAC;
- 网关收到后拆掉帧首部,查路由表定下一跳,换上新的帧首部再发出;
- 逐跳重写 MAC,直到最后一跳路由器发现目标就在自己直连网段,才 ARP 出目标的真实 MAC 投递。
一句话:IP 端到端寻址(全程不变),MAC 逐跳转发(每跳重写)。
网关到底是什么?默认网关的作用?
网关实质上是一个网络通向其他网络的出口 IP 地址,通常就是路由器在本网段的那个地址。
作用:当主机发现目标 IP 不在本网段时,就把数据包交给网关,由网关负责转发出去。没有网关,不同网段之间无法通信——即使物理上连在同一台交换机上,TCP/IP 也会根据子网掩码判定它们不可直达。
默认网关是"不知道该走哪个网关时就走这个",一台主机可以有多个网关但通常只有一个默认网关。
查看:ip route(Linux)、route -n get default(macOS)。
NAT 是什么?解决什么问题?
NAT(Network Address Translation,网络地址转换)在数据包经过路由器时改写源/目的 IP 和端口,并维护一张转换表。
解决 IPv4 地址不足:公网 IP 有限,而私有地址(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)在公网上不可路由。NAT 让整个内网共用一个公网 IP 出去,靠端口号区分不同的内部主机。
副作用:
- 破坏了端到端连通性,外部无法主动连入内网主机(需要端口映射或 NAT 穿透);
- NAT 表项有空闲超时,长连接需要心跳保活,否则映射被清掉就静默断连(见 网络-10);
- 这也是
tcp_tw_recycle在 NAT 环境下有害的原因——同一出口 IP 后面是无数客户端,时间戳不满足递增。
静态路由和动态路由的区别?BGP 是什么?
- 静态路由:管理员手工配置。简单可控无开销,但网段多了难维护,拓扑变化不会自动跟进。
- 动态路由:路由器之间交换信息、自主学习,拓扑变化能自动收敛。
常见协议:
| 协议 | 类型 | 度量依据 | 范围 |
|---|---|---|---|
| RIP | 距离矢量 | 跳数(最多 15) | 小型网络,基本淘汰 |
| OSPF | 链路状态 | 链路开销 | 企业/园区内部 |
| BGP | 路径矢量 | 策略 | 互联网骨干、AS 之间 |
BGP 是整个互联网的粘合剂——运营商之间靠它交换"我能到达哪些网段"。它基于策略而非单纯最短路径,也因此几次著名的大范围断网事故都源于 BGP 配置错误(错误宣告了不属于自己的网段,把全球流量吸引过去)。
路由表有多条规则都能匹配时选哪一条?
先选最长前缀匹配,也就是范围最小、最精确的路由。例如 10.0.0.0/8、10.10.0.0/16 和 10.10.20.0/24 都能匹配 10.10.20.8,最终选择 /24。
前缀长度相同时再比较 metric 等属性。Linux 用 ip route get <目标> 可以直接查看内核最终选择。
conntrack 表满了有什么表现?和端口耗尽怎么区分?
conntrack 表满通常表现为已有连接正常、新连接间歇超时,内核可能记录 nf_conntrack: table full, dropping packet。检查 nf_conntrack_count/max。
本机临时端口耗尽常见错误是 cannot assign requested address,并伴随大量短连接/TIME_WAIT。经过 NAT 时还可能耗尽网关的映射端口。共同的首选解法是复用连接、限制并发,而不是只调大参数。
参考文章: https://www.cnblogs.com/songQQ/archive/2009/05/27/1490612.html
xingliuhua