mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-16 18:10:13 +08:00
[docs add]NAT 协议详解(网络层)
This commit is contained in:
parent
1e70a902ee
commit
0fa55ed949
@ -150,6 +150,7 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
|
||||
- [TCP 三次握手和四次挥手(传输层)](./docs/cs-basics/network/tcp-connection-and-disconnection.md)
|
||||
- [TCP 传输可靠性保障(传输层)](./docs/cs-basics/network/tcp-reliability-guarantee.md)
|
||||
- [ARP 协议详解(网络层)](./docs/cs-basics/network/arp.md)
|
||||
- [NAT 协议详解(网络层)](./docs/cs-basics/network/nat.md)
|
||||
- [网络攻击常见手段总结(安全)](./docs/cs-basics/network/network-attack-means.md)
|
||||
|
||||
### 数据结构
|
||||
|
@ -184,6 +184,7 @@ export default sidebar({
|
||||
"tcp-connection-and-disconnection",
|
||||
"tcp-reliability-guarantee",
|
||||
"arp",
|
||||
"nat",
|
||||
"network-attack-means",
|
||||
],
|
||||
},
|
||||
|
@ -1,3 +1,3 @@
|
||||
$theme-color: #2980b9;
|
||||
// $sidebar-width: 20rem;
|
||||
// $sidebar-mobile-width: 16rem;
|
||||
$sidebar-width: 20rem;
|
||||
$sidebar-mobile-width: 16rem;
|
||||
|
@ -19,7 +19,9 @@ export default hopeTheme({
|
||||
|
||||
repo: "https://github.com/Snailclimb/JavaGuide",
|
||||
docsDir: "docs",
|
||||
|
||||
// 纯净模式:https://theme-hope.vuejs.press/zh/guide/interface/pure.html
|
||||
pure: true,
|
||||
breadcrumb: false,
|
||||
navbar,
|
||||
sidebar,
|
||||
footer:
|
||||
|
56
docs/cs-basics/network/nat.md
Normal file
56
docs/cs-basics/network/nat.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: NAT 协议详解(网络层)
|
||||
category: 计算机基础
|
||||
tag:
|
||||
- 计算机网络
|
||||
---
|
||||
|
||||
## 应用场景
|
||||
|
||||
**NAT 协议(Network Address Translation)** 的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(WAN)中,需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。
|
||||
|
||||
这个场景其实不难理解。随着一个个小型办公室、家庭办公室(Small Office, Home Office, SOHO)的出现,为了管理这些 SOHO,一个个子网被设计出来,从而在整个 Internet 中的主机数量将非常庞大。如果每个主机都有一个“绝对唯一”的 IP 地址,那么 IPv4 地址的表达能力可能很快达到上限($2^{32}$)。因此,实际上,SOHO 子网中的 IP 地址是“相对的”,这在一定程度上也缓解了 IPv4 地址的分配压力。
|
||||
|
||||
SOHO 子网的“代理人”,也就是和外界的窗口,通常由路由器扮演。路由器的 LAN 一侧管理着一个小子网,而它的 WAN 接口才是真正参与到 Internet 中的接口,也就有一个“绝对唯一的地址”。NAT 协议,正是在 LAN 中的主机在与 LAN 外界通信时,起到了地址转换的关键作用。
|
||||
|
||||
## 细节
|
||||
|
||||

|
||||
|
||||
假设当前场景如上图。中间是一个路由器,它的右侧组织了一个 WAN,该局域网的网络号为`10.0.0/24`,WAN 侧接口的 IP 地址为`10.0.0.4`,并且该子网内有至少三台主机,分别是`10.0.0.1`,`10.0.0.2`和`10.0.0.3`。路由器的左侧连接的是 WAN,WAN 侧接口的 IP 地址为`138.76.29.7`。
|
||||
|
||||
首先,针对以上信息,我们有如下事实需要说明:
|
||||
|
||||
1. 路由器的右侧子网的网络号为`10.0.0/24`,主机号为`10.0.0/8`,三台主机地址,以及路由器的 LAN 侧接口地址,均由 DHCP 协议规定。而且,该 DHCP 运行在路由器内部(路由器自维护一个小 DHCP 服务器),从而为子网内提供 DHCP 服务。
|
||||
2. 路由器的 WAN 侧接口地址同样由 DHCP 协议规定,但该地址是路由器从 ISP(网络服务提供商)处获得,也就是该 DHCP 通常运行在路由器所在区域的 DHCP 服务器上。
|
||||
|
||||
现在,路由器内部还运行着 NAT 协议,从而为 LAN-WAN 间通信提供地址转换服务。为此,一个很重要的结构是 **NAT 转换表**。为了说明 NAT 的运行细节,假设有以下请求发生:
|
||||
|
||||
1. 主机`10.0.0.1`向 IP 地址为`128.119.40.186`的 Web 服务器(端口 80)发送了 HTTP 请求(如请求页面)。此时,主机`10.0.0.1`将随机指派一个端口,如`3345`,作为本次请求的源端口号,将该请求发送到路由器中(目的地址将是`128.119.40.186`,但会先到达`10.0.0.4`)。
|
||||
2. `10.0.0.4`即路由器的 LAN 接口收到`10.0.0.1`的请求。路由器将为该请求指派一个新的源端口号,如`5001`,并将请求报文发送给 WAN 接口`138.76.29.7`。同时,在 NAT 转换表中记录一条转换记录**138.76.29.7:5001——10.0.0.1:3345**。
|
||||
3. 请求报文到达 WAN 接口,继续向目的主机`128.119.40.186`发送。
|
||||
|
||||
之后,将会有如下响应发生:
|
||||
|
||||
1. 主机`128.119.40.186`收到请求,构造响应报文,并将其发送给目的地`138.76.29.7:5001`。
|
||||
2. 响应报文到达路由器的 WAN 接口。路由器查询 NAT 转换表,发现`138.76.29.7:5001`在转换表中有记录,从而将其目的地址和目的端口转换成为`10.0.0.1:3345`,再发送到`10.0.0.4`上。
|
||||
3. 被转换的响应报文到达路由器的 LAN 接口,继而被转发至目的地`10.0.0.1`。
|
||||
|
||||

|
||||
|
||||
## 划重点
|
||||
|
||||
针对以上过程,有以下几个重点需要强调:
|
||||
|
||||
1. 当请求报文到达路由器,并被指定了新端口号时,由于端口号有 16 位,因此,通常来说,一个路由器管理的 LAN 中的最大主机数 $≈65500$($2^{16}$ 的地址空间),但通常 SOHO 子网内不会有如此多的主机数量。
|
||||
2. 对于目的服务器来说,从来不知道“到底是哪个主机给我发送的请求”,它只知道是来自`138.76.29.7:5001`的路由器转发的请求。因此,可以说,**路由器在 WAN 和 LAN 之间起到了屏蔽作用,**所有内部主机发送到外部的报文,都具有同一个 IP 地址(不同的端口号),所有外部发送到内部的报文,也都只有一个目的地(不同端口号),是经过了 NAT 转换后,外部报文才得以正确地送达内部主机。
|
||||
3. 在报文穿过路由器,发生 NAT 转换时,如果 LAN 主机 IP 已经在 NAT 转换表中注册过了,则不需要路由器新指派端口,而是直接按照转换记录穿过路由器。同理,外部报文发送至内部时也如此。
|
||||
|
||||
总结 NAT 协议的特点,有以下几点:
|
||||
|
||||
1. NAT 协议通过对 WAN 屏蔽 LAN,有效地缓解了 IPv4 地址分配压力。
|
||||
2. LAN 主机 IP 地址的变更,无需通告 WAN。
|
||||
3. WAN 的 ISP 变更接口地址时,无需通告 LAN 内主机。
|
||||
4. LAN 主机对 WAN 不可见,不可直接寻址,可以保证一定程度的安全性。
|
||||
|
||||
然而,NAT 协议由于其独特性,存在着一些争议。比如,可能你已经注意到了,**NAT 协议在 LAN 以外,标识一个内部主机时,使用的是端口号,因为 IP 地址都是相同的。**这种将端口号作为主机寻址的行为,可能会引发一些误会。此外,路由器作为网络层的设备,修改了传输层的分组内容(修改了源 IP 地址和端口号),同样是不规范的行为。但是,尽管如此,NAT 协议作为 IPv4 时代的产物,极大地方便了一些本来棘手的问题,一直被沿用至今。
|
@ -17,7 +17,7 @@ tag:
|
||||
- **二次握手**:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 **SYN_RECV** 状态
|
||||
- **三次握手**:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务器端都进入**ESTABLISHED** 状态,完成 TCP 三次握手。
|
||||
|
||||
**当建立了 3 次握手之后,客户端和服务端就可以传输数据啦!**
|
||||
当建立了 3 次握手之后,客户端和服务端就可以传输数据啦!
|
||||
|
||||
### 为什么要三次握手?
|
||||
|
||||
@ -43,10 +43,10 @@ tag:
|
||||
|
||||
断开一个 TCP 连接则需要“四次挥手”,缺一不可 :
|
||||
|
||||
1. **第一次挥手** :客户端发送一个 FIN(SEQ=X) 标志的数据包->服务端,用来关闭客户端到服务器的数据传送。然后,客户端进入 **FIN-WAIT-1** 状态。
|
||||
2. **第二次挥手** :服务器收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (SEQ=X+1)标志的数据包->客户端 。然后,此时服务端进入**CLOSE-WAIT**状态,客户端进入**FIN-WAIT-2**状态。
|
||||
1. **第一次挥手** :客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务器的数据传送。然后,客户端进入 **FIN-WAIT-1** 状态。
|
||||
2. **第二次挥手** :服务器收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (ACK=x+1)标志的数据包->客户端 。然后,此时服务端进入 **CLOSE-WAIT** 状态,客户端进入 **FIN-WAIT-2** 状态。
|
||||
3. **第三次挥手** :服务端关闭与客户端的连接并发送一个 FIN (SEQ=y)标志的数据包->客户端请求关闭连接,然后,服务端进入 **LAST-ACK** 状态。
|
||||
4. **第四次挥手** :客户端发送 ACK (SEQ=y+1)标志的数据包->服务端并且进入**TIME-WAIT**状态,服务端在收到 ACK (SEQ=y+1)标志的数据包后进入 CLOSE 状态。此时,如果客户端等待 **2MSL** 后依然没有收到回复,就证明服务端已正常关闭,随后,客户端也可以关闭连接了。
|
||||
4. **第四次挥手** :客户端发送 ACK (ACK=y+1)标志的数据包->服务端并且进入**TIME-WAIT**状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时,如果客户端等待 **2MSL** 后依然没有收到回复,就证明服务端已正常关闭,随后,客户端也可以关闭连接了。
|
||||
|
||||
**只要四次挥手没有结束,客户端和服务端就可以继续传输数据!**
|
||||
|
||||
|
@ -6,6 +6,7 @@ tag:
|
||||
---
|
||||
|
||||
**缓存基础** 相关的面试题为我的[知识星球](https://javaguide.cn/about-the-author/zhishixingqiu-two-years.html)(点击链接即可查看详细介绍以及加入方法)专属内容,已经整理到了[《Java 面试指北》](https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html)中。
|
||||
|
||||

|
||||
|
||||
<!-- @include: @planet.snippet.md -->
|
@ -147,6 +147,7 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8](https://docs.oracle.
|
||||
- [TCP 三次握手和四次挥手(传输层)](./cs-basics/network/tcp-connection-and-disconnection.md)
|
||||
- [TCP 传输可靠性保障(传输层)](./cs-basics/network/tcp-reliability-guarantee.md)
|
||||
- [ARP 协议详解(网络层)](./cs-basics/network/arp.md)
|
||||
- [NAT 协议详解(网络层)](./docs/cs-basics/network/nat.md)
|
||||
- [网络攻击常见手段总结(安全)](./cs-basics/network/network-attack-means.md)
|
||||
|
||||
### 数据结构
|
||||
|
@ -290,6 +290,30 @@ final void treeifyBin(Node<K,V>[] tab, int hash) {
|
||||
|
||||
[HashMap 的 7 种遍历方式与性能分析!](https://mp.weixin.qq.com/s/zQBN3UvJDhRTKP6SzcZFKw)
|
||||
|
||||
**🐛 修正(参见: [issue#1411](https://github.com/Snailclimb/JavaGuide/issues/1411))** :
|
||||
|
||||
这篇文章对于 parallelStream 遍历方式的性能分析有误,先说结论: **存在阻塞时 parallelStream 性能最高, 非阻塞时 parallelStream 性能最低** 。
|
||||
|
||||
当遍历不存在阻塞时, parallelStream 的性能是最低的:
|
||||
|
||||
```
|
||||
Benchmark Mode Cnt Score Error Units
|
||||
Test.entrySet avgt 5 288.651 ± 10.536 ns/op
|
||||
Test.keySet avgt 5 584.594 ± 21.431 ns/op
|
||||
Test.lambda avgt 5 221.791 ± 10.198 ns/op
|
||||
Test.parallelStream avgt 5 6919.163 ± 1116.139 ns/op
|
||||
```
|
||||
|
||||
加入阻塞代码`Thread.sleep(10)`后, parallelStream 的性能才是最高的:
|
||||
|
||||
```
|
||||
Benchmark Mode Cnt Score Error Units
|
||||
Test.entrySet avgt 5 1554828440.000 ± 23657748.653 ns/op
|
||||
Test.keySet avgt 5 1550612500.000 ± 6474562.858 ns/op
|
||||
Test.lambda avgt 5 1551065180.000 ± 19164407.426 ns/op
|
||||
Test.parallelStream avgt 5 186345456.667 ± 3210435.590 ns/op
|
||||
```
|
||||
|
||||
### ConcurrentHashMap 和 Hashtable 的区别
|
||||
|
||||
`ConcurrentHashMap` 和 `Hashtable` 的区别主要体现在实现线程安全的方式上不同。
|
||||
|
Loading…
x
Reference in New Issue
Block a user