👋 关于作者
你好,这里是一条 泥憨鱼 | 专注于 后端开发 、AI 前沿技术与计算机基础 。

🏠 个人主页 :一条泥憨鱼
通过技术博客记录技术成长,分享学习心得与经验。期待与您共同交流!
📚精选技术专栏:
|-------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| ❄️后端开发 | ❄️Redis| 黑马点评 |
| ❄️从0开始学习计算机网络 | ❄️数据结构与算法 |
| ❄️苍穹外卖 | ❄️探秘AI与agent |

把笔记本插上网线就能上网,而家里那台服务器从公司却怎么也连不进去。这两个现象背后是两套机制:DHCP 负责把地址发下来,NAT 负责把内网流量送出去。
为什么需要 NAT
IPv4 地址是 32 位,理论上约 43 亿个。这个数字在 1990 年代就被认为不够用了,原因不只是设备多,还在于地址分配本身是分块的:早期按 A/B/C 类划分,一个 B 类就吃掉 65536 个地址,很多组织拿到的地址段实际只用了一小部分。IPv6 是最终解法,但迁移成本高、周期长,中间必须有个过渡方案,这就是 NAT。
NAT(Network Address Translation,网络地址转换) 要解决的核心矛盾很具体:内网有一大批设备需要访问公网,但公网只给这个组织分配了少量甚至一个公网地址。
它给出的办法是在内网和公网之间放一个转换点(通常是路由器或防火墙)。内网设备用私有地址(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16 这三段,RFC 1918 规定),这些地址不会出现在公网上。数据包经过转换点时,源地址被改写成公网地址;回来的包再改回内网地址。

代价随之而来。NAT 是有状态的:它必须记住"这个内网地址对应哪个公网地址",才能把回包还原。这意味着外部主机无法主动发起连接------转换表里没有对应条目,包到了就被丢弃。这也是为什么家庭宽带默认无法从外面直接访问内网服务,需要端口映射或内网穿透。另一个副作用是破坏端到端透明性:应用层如果把自己的 IP 写进载荷(比如 SIP、FTP 主动模式),NAT 不知道要改,就会出现连不通的怪问题。
NAT 的三种形态
按映射粒度,NAT 分成三类。理解它们的关键是问一句:内网地址和公网地址之间是几对几的关系?
静态 NAT 是一对一固定映射。管理员手工配好 192.168.1.10 与 203.0.113.5 的对应关系,之后这个内网地址出去永远用这个公网地址。因为映射固定,外部也能通过这个公网地址主动访问进来,常用于把内网服务器发布到公网。缺点是每个内网地址都独占一个公网地址,省不下来。
动态 NAT是一对一轮询。准备一个公网地址池,内网设备要出网时从池里借一个,用完还回去。它比静态 NAT 灵活,但映射粒度仍是一对一,池子里有多少地址就最多支持多少台设备同时出网。设备一多就排队。
NAPT(Network Address Port Translation),也叫 PAT、端口复用,是真正让 IPv4 撑到今天的方案。它把映射粒度降到端口级:多个内网地址可以共用一个公网地址,靠不同的源端口区分。一台家用路由器只有一个公网 IP,却能让手机、电脑、电视同时上网,靠的就是它。
| 类型 | 映射粒度 | 公网地址需求 | 外部能否主动访问 |
| 静态 NAT | 一对一固定 | 每个内网地址一个 | 能 |
| 动态 NAT | 一对一轮询 | 池大小决定并发 | 不能(映射不固定) |
| NAPT/PAT | 多对一,按端口区分 | 可仅一个 | 不能(除非配端口映射) |
主流是 NAPT,原因很直接:在地址最紧张的场景下,它把"地址"这个稀缺资源换成了"端口"这个相对充裕的资源。一个公网 IP 有 65535 个端口可用,理论上能支撑数万个并发会话。
NAPT 内部如何运转
NAPT 的核心是一张转换表,出站时建表,入站时查表。整条链路分两个方向。
出站方向,内网主机发出一个包,源地址是 192.168.1.10:50000,目标是公网某服务器 198.51.100.20:80。转换节点收到后做三件事:
给这个会话分配一个公网源端口,比如 40001;
记录一条表项:内网 192.168.1.10:50000 与公网 203.0.113.5:40001 的对应关系,对端 198.51.100.20:80;
改写报文头,源地址变成 203.0.113.5:40001,转发出去。
报文改写前后的对比大致是这样:
出站前:192.168.1.10:50000 -> 198.51.100.20:80
出站后:203.0.113.5:40001 -> 198.51.100.20:80
入站前:198.51.100.20:80 -> 203.0.113.5:40001
入站后:198.51.100.20:80 -> 192.168.1.10:50000

入站方向反过来。服务器回包,目标地址是 203.0.113.5:40001。转换节点拿目的端口 40001 去查表,找到对应内网地址 192.168.1.10:50000,把目的地址改写回去,再转发给内网主机。
这里有个容易忽略的细节:查表不只看端口,还要看协议和对端地址。 因为 TCP 和 UDP 的端口空间是独立的,同一个端口号 40001 可以同时被 TCP 和 UDP 占用;对端地址用来区分不同会话,避免误匹配。

所以 NAT 的本质是连接状态。表项存在,回包能还原;表项不存在,包直接被丢。这也解释了前面那个现象:外部主动连进来时,表里没有对应条目,包无处可去。表项还有生存时间,TCP 会话结束后会保留一段时间(常见几十秒到几分钟),UDP 因为没有明确的结束信号,超时通常更短。会话空闲太久,表项被清理,再来的回包就会被丢弃------这是长连接应用在 NAT 环境下偶发断连的原因之一,通常需要靠心跳保活。
DHCP 四步握手
**DHCP(Dynamic Host Configuration Protocol)**解决的问题正好相反:设备刚接入网络时,既没有 IP,也不知道网关和 DNS 是谁,怎么把地址发到它手上?
答案是四步握手,名词很好记:Discover、Offer、Request、ACK。
Discover:客户端以广播方式发出,源地址 0.0.0.0,目的地址 255.255.255.255,意思是"谁是 DHCP 服务器,我需要地址"。因为客户端此时没有任何地址,只能用广播。
Offer:服务器收到后,从地址池里挑一个可用地址,回一个 Offer,里面带上 IP、子网掩码、网关、DNS、租约时长。如果网络里有多个 DHCP 服务器,客户端可能收到多个 Offer。
Request:客户端从收到的 Offer 里选一个,广播发出 Request,告诉所有服务器"我要用这个地址"。这一步是关键------因为它是广播,其他服务器看到后会收回自己刚才的 Offer,把地址放回池子。如果没有这一步,多个服务器都以为自己分配成功,就会出现地址冲突。
ACK:被选中的服务器确认,客户端正式获得地址,可以开始通信。

地址不是永久给的,而是租约。租约到期前,客户端会尝试续租:先单播给原服务器发 Request,服务器回 ACK 续期。如果原服务器没响应,租约过半后会向整个网段广播续租请求。租约彻底过期还没续上,客户端就得重新走一遍 Discover 流程。租约机制的好处是地址可以回收再利用------设备拔走之后,地址不会永远占着。
为什么 DHCP 基于 UDP
这里有个鸡生蛋的问题:客户端还没有 IP,怎么通信?
TCP 要求先建立连接,而建立连接需要双方都能收发报文,意味着双方都得有地址。客户端此刻连自己的地址都没有,TCP 根本不成立。UDP 是无连接的,发出去就不管,不需要预先握手,正好适配这个场景。
具体到地址使用,DHCP 有几个边界细节:
客户端发 Discover 和 Request 时,源地址是 0.0.0.0,目的地址是 255.255.255.255。0.0.0.0 表示"我还没有地址",广播表示"我不知道服务器在哪,全网喊一声"。
服务器回 Offer 和 ACK 时,如果客户端还不能接收单播(有些系统要求先完成配置才能收单播),服务器会用广播;否则用单播。
端口固定:服务器监听 67,客户端监听 68。
还有一个常被忽略的设计:DHCP 报文可以带一个 giaddr(网关 IP 地址)字段,用来支持跨网段分配。因为广播不能穿过路由器,如果 DHCP 服务器和客户端不在同一个网段,就需要中继代理(DHCP Relay)把广播转成单播发给服务器,并在 giaddr 里填上自己的地址,服务器据此判断该从哪个地址池分配。企业网络里一台 DHCP 服务器管多个 VLAN,靠的就是这个。
收束
回到开头那两个现象:能上网说明 NAT 和 DHCP 都在正常工作,从外面连不进来说明 NAT 表里没有对应条目。这两件事的机理可以概括成一句话:NAT 靠状态,DHCP 靠广播。
排查内网访问问题时,先分清是地址分配层还是地址转换层。设备拿不到 IP、拿到的是 169.254.x.x,问题在 DHCP------检查地址池是否耗尽、中继是否配好、服务器是否可达。设备有正常 IP 但访问不了外网、或者外部连不进来,问题在 NAT------看转换表有没有对应条目、端口映射是否配置、会话是否已超时被清理。