当前位置:网站首页 > 技术博客 > 正文

网页 访问



开发岗中总是会考很多计算机网络的知识点,但如果让面试官只靠一道题,便涵盖最多的计网知识点,那可能就是 网页浏览的全过程 了。本篇文章将带大家从头到尾过一遍这道被考烂的面试题,必会!!!

总的来说,网络通信模型可以用下图来表示,也就是大家只要熟记网络结构五层模型,按照这个体系,很多知识点都能顺出来了。访问网页的过程也是如此。

开始之前,我们先简单过一遍完整流程:

  1. 在浏览器中输入指定网页的 URL。
  2. 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
  3. 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
  4. 浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
  5. 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
  6. 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
  7. 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。

一切的开始——打开浏览器,在地址栏输入 URL,回车确认。那么,什么是 URL?访问 URL 有什么用?

URL(Uniform Resource Locators),即统一资源定位器。网络上的所有资源都靠 URL 来定位,每一个文件就对应着一个 URL,就像是路径地址。理论上,文件资源和 URL 一一对应。实际上也有例外,比如某些 URL 指向的文件已经被重定位到另一个位置,这样就有多个 URL 指向同一个文件。

URL的组成结构
URL的组成结构
  1. 协议。URL 的前缀通常表示了该网址采用了何种应用层协议,通常有两种——HTTP 和 HTTPS。当然也有一些不太常见的前缀头,比如文件传输时用到的。
  2. 域名。域名便是访问网址的通用名,这里也有可能是网址的 IP 地址,域名可以理解为 IP 地址的可读版本,毕竟绝大部分人都不会选择记住一个网址的 IP 地址。
  3. 端口。如果指明了访问网址的端口的话,端口会紧跟在域名后面,并用一个冒号隔开。
  4. 资源路径。域名(端口)后紧跟的就是资源路径,从第一个开始,表示从服务器上根目录开始进行索引到的文件路径,上图中要访问的文件就是服务器根目录下。早先的设计是该文件通常物理存储于服务器主机上,但现在随着网络技术的进步,该文件不一定会物理存储在服务器主机上,有可能存放在云上,而文件路径也有可能是虚拟的(遵循某种规则)。
  5. 参数。参数是浏览器在向服务器提交请求时,在 URL 中附带的参数。服务器解析请求时,会提取这些参数。参数采用键值对的形式,每一个键值对使用隔开。参数的具体含义和请求操作的具体方法有关。
  6. 锚点。锚点顾名思义,是在要访问的页面上的一个锚。要访问的页面大部分都多于一页,如果指定了锚点,那么在客户端显示该网页是就会定位到锚点处,相当于一个小书签。值得一提的是,在 URL 中,锚点以开头,并且不会作为请求的一部分发送给服务端。

键入了 URL 之后,第一个重头戏登场——DNS 服务器解析。DNS(Domain Name System)域名系统,要解决的是 域名和 IP 地址的映射问题 。毕竟,域名只是一个网址便于记住的名字,而网址真正存在的地址其实是 IP 地址。

传送门:DNS 域名系统详解(应用层)

利用 DNS 拿到了目标主机的 IP 地址之后,浏览器便可以向目标 IP 地址发送 HTTP 报文,请求需要的资源了。在这里,根据目标网站的不同,请求报文可能是 HTTP 协议或安全性增强的 HTTPS 协议。

传送门:

  • HTTP vs HTTPS(应用层)
  • HTTP 1.0 vs HTTP 1.1(应用层)
  • HTTP 常见状态码总结(应用层)

由于 HTTP 协议是基于 TCP 协议的,在应用层的数据封装好以后,要交给传输层,经 TCP 协议继续封装。

TCP 协议保证了数据传输的可靠性,是数据包传输的主力协议。

传送门:

  • TCP 三次握手和四次挥手(传输层)
  • TCP 传输可靠性保障(传输层)

终于,来到网络层,此时我们的主机不再是和另一台主机进行交互了,而是在和中间系统进行交互。也就是说,应用层和传输层都是端到端的协议,而网络层及以下都是中间件的协议了。

网络层的的核心功能——转发与路由,必会!!!如果面试官问到了网络层,而你恰好又什么都不会的话,最最起码要说出这五个字——转发与路由

  • 转发:将分组从路由器的输入端口转移到合适的输出端口。
  • 路由:确定分组从源到目的经过的路径。

所以到目前为止,我们的数据包经过了应用层、传输层的封装,来到了网络层,终于开始准备在物理层面传输了,第一个要解决的问题就是——往哪里传输?或者说,要把数据包发到哪个路由器上?这便是 BGP 协议要解决的问题。

超文本传输协议(HTTP,HyperText Transfer Protocol) 是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。

HTTP 使用客户端-服务器模型,客户端向服务器发送 HTTP Request(请求),服务器响应请求并返回 HTTP Response(响应),整个过程如下图所示。

HTTP 协议基于 TCP 协议,发送 HTTP 请求之前首先要建立 TCP 连接也就是要经历 3 次握手。目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样的话建立的连接就可以在多次请求中被复用了。

另外, HTTP 协议是”无状态”的协议,它无法记录客户端用户的状态,一般我们都是通过 Session 来记录客户端用户的状态。

WebSocket 是一种基于 TCP 连接的全双工通信协议,即客户端和服务器可以同时发送和接收数据。

WebSocket 协议在 2008 年诞生,2011 年成为国际标准,几乎所有主流较新版本的浏览器都支持该协议。不过,WebSocket 不只能在基于浏览器的应用程序中使用,很多编程语言、框架和服务器都提供了 WebSocket 支持。

WebSocket 协议本质上是应用层的协议,用于弥补 HTTP 协议在持久通信能力上的不足。客户端和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

Websocket 示意图
Websocket 示意图

下面是 WebSocket 的常见应用场景:

  • 视频弹幕
  • 实时消息推送,详见Web 实时消息推送详解这篇文章
  • 实时游戏对战
  • 多用户协同编辑
  • 社交聊天
  • ……

WebSocket 的工作过程可以分为以下几个步骤:

  1. 客户端向服务器发送一个 HTTP 请求,请求头中包含 和 等字段,表示要求升级协议为 WebSocket;
  2. 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 ,和 等字段、表示成功升级到 WebSocket 协议。
  3. 客户端和服务器之间建立了一个 WebSocket 连接,可以进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。
  4. 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。

另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性。

简单邮件传输(发送)协议(SMTP,Simple Mail Transfer Protocol) 基于 TCP 协议,是一种用于发送电子邮件的协议

SMTP 协议
SMTP 协议

注意 ⚠️:接受邮件的协议不是 SMTP 而是 POP3 协议。

SMTP 协议这块涉及的内容比较多,下面这两个问题比较重要:

  1. 电子邮件的发送过程
  2. 如何判断邮箱是真正存在的?

电子邮件的发送过程?

比如我的邮箱是“”,我要向“”发送邮件,整个过程可以简单分为下面几步:

  1. 通过 SMTP 协议,我将我写好的邮件交给 163 邮箱服务器(邮局)。
  2. 163 邮箱服务器发现我发送的邮箱是 邮箱,然后它使用 SMTP 协议将我的邮件转发到 邮箱服务器。
  3. 邮箱服务器接收邮件之后就通知邮箱为“”的用户来收邮件,然后用户就通过 POP3/IMAP 协议将邮件取出。

如何判断邮箱是真正存在的?

很多场景(比如邮件营销)下面我们需要判断我们要发送的邮箱地址是否真的存在,这个时候我们可以利用 SMTP 协议来检测:

  1. 查找邮箱域名对应的 SMTP 服务器地址
  2. 尝试与服务器建立连接
  3. 连接成功后尝试向需要验证的邮箱发送邮件
  4. 根据返回结果判定邮箱地址的真实性

推荐几个在线邮箱是否有效检测工具:

  1. https://verify-email.org/
  2. http://tool.chacuo.net/mailverify
  3. https://www.emailcamel.com/

这两个协议没必要多做阐述,只需要了解 POP3 和 IMAP 两者都是负责邮件接收的协议 即可(二者也是基于 TCP 协议)。另外,需要注意不要将这两者和 SMTP 协议搞混淆了。SMTP 协议只负责邮件的发送,真正负责接收的协议是 POP3/IMAP。

IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。

FTP 协议 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。

FTP 是基于客户—服务器(C/S)模型而设计的,在客户端与 FTP 服务器之间建立两个连接。如果我们要基于 FTP 协议开发一个文件传输的软件的话,首先需要搞清楚 FTP 的原理。关于 FTP 的原理,很多书籍上已经描述的非常详细了:

FTP 的独特的优势同时也是与其它客户服务器程序最大的不同点就在于它在两台通信的主机之间使用了两条 TCP 连接(其它客户服务器应用程序一般只有一条 TCP 连接):

  1. 控制连接:用于传送控制信息(命令和响应)
  2. 数据连接:用于数据传送;

这种将命令和数据分开传送的思想大大提高了 FTP 的效率。

FTP工作过程
FTP工作过程

注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。因此,FTP 传输的文件可能会被窃听或篡改。建议在传输敏感数据时使用更安全的协议,如 SFTP(SSH File Transfer Protocol,一种基于 SSH 协议的安全文件传输协议,用于在网络上安全地传输文件)。

Telnet 协议 基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。

Telnet:远程登陆协议
Telnet:远程登陆协议

SSH(Secure Shell) 基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务。

SSH 的经典用途是登录到远程电脑中执行命令。除此之外,SSH 也支持隧道协议、端口映射和 X11 连接(允许用户在本地运行远程服务器上的图形应用程序)。借助 SFTP(SSH File Transfer Protocol) 或 SCP(Secure Copy Protocol) 协议,SSH 还可以安全传输文件。

SSH 使用客户端-服务器模型,默认端口是 22。SSH 是一个守护进程,负责实时监听客户端请求,并进行处理。大多数现代操作系统都提供了 SSH。

如下图所示,SSH Client(SSH 客户端)和 SSH Server(SSH 服务器)通过公钥交换生成共享的对称加密密钥,用于后续的加密通信。

SSH:安全的网络传输协议
SSH:安全的网络传输协议

RTP(Real-time Transport Protocol,实时传输协议)通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。

RTP 协议分为两种子协议:

  • RTP(Real-time Transport Protocol,实时传输协议):传输具有实时特性的数据。
  • RTCP(RTP Control Protocol,RTP 控制协议):提供实时传输过程中的统计信息(如网络延迟、丢包率等),WebRTC 正是根据这些信息处理丢包

DNS(Domain Name System,域名管理系统)基于 UDP 协议,用于解决域名和 IP 地址的映射问题。

DNS:域名系统
DNS:域名系统
  • 《计算机网络自顶向下方法》(第七版)
  • RTP 协议介绍:https://mthli.xyz/rtp-introduction/
JavaGuide 官方公众号
JavaGuide 官方公众号

HTTP 协议,全称超文本传输协议(Hypertext Transfer Protocol)。顾名思义,HTTP 协议就是用来规范超文本的传输,超文本,也就是网络上的包括文本在内的各式各样的消息,具体来说,主要是来规范浏览器和服务器端的行为的。

并且,HTTP 是一个无状态(stateless)协议,也就是说服务器不维护任何有关客户端过去所发请求的消息。这其实是一种懒政,有状态协议会更加复杂,需要维护状态(历史信息),而且如果客户或服务器失效,会产生状态的不一致,解决这种不一致的代价更高。

HTTP 是应用层协议,它以 TCP(传输层)作为底层协议,默认端口为 80. 通信过程主要如下:

  1. 服务器在 80 端口等待客户的请求。
  2. 浏览器发起到服务器的 TCP 连接(创建套接字 Socket)。
  3. 服务器接收来自浏览器的 TCP 连接。
  4. 浏览器(HTTP 客户端)与 Web 服务器(HTTP 服务器)交换 HTTP 消息。
  5. 关闭 TCP 连接。

扩展性强、速度快、跨平台支持性好。

HTTPS 协议(Hyper Text Transfer Protocol Secure),是 HTTP 的加强安全版本。HTTPS 是基于 HTTP 的,也是用 TCP 作为底层协议,并额外使用 SSL/TLS 协议用作加密和安全认证。默认端口号是 443.

HTTPS 协议中,SSL 通道通常使用基于密钥的加密算法,密钥长度通常是 40 比特或 128 比特。

保密性好、信任度高。

HTTPS 之所以能达到较高的安全性要求,就是结合了 SSL/TLS 和 TCP 协议,对通信数据进行加密,解决了 HTTP 数据透明的问题。接下来重点介绍一下 SSL/TLS 的工作原理。

SSL 和 TLS 没有太大的区别。

SSL 指安全套接字协议(Secure Sockets Layer),首次发布与 1996 年。SSL 的首次发布其实已经是他的 3.0 版本,SSL 1.0 从未面世,SSL 2.0 则具有较大的缺陷(DROWN 缺陷——Decrypting RSA with Obsolete and Weakened eNcryption)。很快,在 1999 年,SSL 3.0 进一步升级,新版本被命名为 TLS 1.0。因此,TLS 是基于 SSL 之上的,但由于习惯叫法,通常把 HTTPS 中的核心加密协议混称为 SSL/TLS。

SSL/TLS 的核心要素是非对称加密。非对称加密采用两个密钥——一个公钥,一个私钥。在通信时,私钥仅由解密者保存,公钥由任何一个想与解密者通信的发送者(加密者)所知。可以设想一个场景,

在某个自助邮局,每个通信信道都是一个邮箱,每一个邮箱所有者都在旁边立了一个牌子,上面挂着一把钥匙:这是我的公钥,发送者请将信件放入我的邮箱,并用公钥锁好。

但是公钥只能加锁,并不能解锁。解锁只能由邮箱的所有者——因为只有他保存着私钥。

这样,通信信息就不会被其他人截获了,这依赖于私钥的保密性。

非对称加密的公钥和私钥需要采用一种复杂的数学机制生成(密码学认为,为了较高的安全性,尽量不要自己创造加密方案)。公私钥对的生成算法依赖于单向陷门函数。

单向函数:已知单向函数 f,给定任意一个输入 x,易计算输出 y=f(x);而给定一个输出 y,假设存在 f(x)=y,很难根据 f 来计算出 x。

单向陷门函数:一个较弱的单向函数。已知单向陷门函数 f,陷门 h,给定任意一个输入 x,易计算出输出 y=f(x;h);而给定一个输出 y,假设存在 f(x;h)=y,很难根据 f 来计算出 x,但可以根据 f 和 h 来推导出 x。

单向函数
单向函数

上图就是一个单向函数(不是单项陷门函数),假设有一个绝世秘籍,任何知道了这个秘籍的人都可以把苹果汁榨成苹果,那么这个秘籍就是“陷门”了吧。

在这里,函数 f 的计算方法相当于公钥,陷门 h 相当于私钥。公钥 f 是公开的,任何人对已有输入,都可以用 f 加密,而要想根据加密信息还原出原信息,必须要有私钥才行。

使用 SSL/TLS 进行通信的双方需要使用非对称加密方案来通信,但是非对称加密设计了较为复杂的数学算法,在实际通信过程中,计算的代价较高,效率太低,因此,SSL/TLS 实际对消息的加密使用的是对称加密。

对称加密:通信双方共享唯一密钥 k,加解密算法已知,加密方利用密钥 k 加密,解密方利用密钥 k 解密,保密性依赖于密钥 k 的保密性。

对称加密的密钥生成代价比公私钥对的生成代价低得多,那么有的人会问了,为什么 SSL/TLS 还需要使用非对称加密呢?因为对称加密的保密性完全依赖于密钥的保密性。在双方通信之前,需要商量一个用于对称加密的密钥。我们知道网络通信的信道是不安全的,传输报文对任何人是可见的,密钥的交换肯定不能直接在网络信道中传输。因此,使用非对称加密,对对称加密的密钥进行加密,保护该密钥不在网络信道中被窃听。这样,通信双方只需要一次非对称加密,交换对称加密的密钥,在之后的信息通信中,使用绝对安全的密钥,对信息进行对称加密,即可保证传输消息的保密性。

SSL/TLS 介绍到这里,了解信息安全的朋友又会想到一个安全隐患,设想一个下面的场景:

客户端 C 和服务器 S 想要使用 SSL/TLS 通信,由上述 SSL/TLS 通信原理,C 需要先知道 S 的公钥,而 S 公钥的唯一获取途径,就是把 S 公钥在网络信道中传输。要注意网络信道通信中有几个前提:

  1. 任何人都可以捕获通信包
  2. 通信包的保密性由发送者设计
  3. 保密算法设计方案默认为公开,而(解密)密钥默认是安全的

因此,假设 S 公钥不做加密,在信道中传输,那么很有可能存在一个攻击者 A,发送给 C 一个诈包,假装是 S 公钥,其实是诱饵服务器 AS 的公钥。当 C 收获了 AS 的公钥(却以为是 S 的公钥),C 后续就会使用 AS 公钥对数据进行加密,并在公开信道传输,那么 A 将捕获这些加密包,用 AS 的私钥解密,就截获了 C 本要给 S 发送的内容,而 C 和 S 二人全然不知。

同样的,S 公钥即使做加密,也难以避免这种信任性问题,C 被 AS 拐跑了!

为了公钥传输的信赖性问题,第三方机构应运而生——证书颁发机构(CA,Certificate Authority)。CA 默认是受信任的第三方。CA 会给各个服务器颁发证书,证书存储在服务器上,并附有 CA 的电子签名(见下节)。

当客户端(浏览器)向服务器发送 HTTPS 请求时,一定要先获取目标服务器的证书,并根据证书上的信息,检验证书的合法性。一旦客户端检测到证书非法,就会发生错误。客户端获取了服务器的证书后,由于证书的信任性是由第三方信赖机构认证的,而证书上又包含着服务器的公钥信息,客户端就可以放心的信任证书上的公钥就是目标服务器的公钥。

好,到这一小节,已经是 SSL/TLS 的尾声了。上一小节提到了数字签名,数字签名要解决的问题,是防止证书被伪造。第三方信赖机构 CA 之所以能被信赖,就是 靠数字签名技术

数字签名,是 CA 在给服务器颁发证书时,使用散列+加密的组合技术,在证书上盖个章,以此来提供验伪的功能。具体行为如下:

CA 知道服务器的公钥,对证书采用散列技术生成一个摘要。CA 使用 CA 私钥对该摘要进行加密,并附在证书下方,发送给服务器。

现在服务器将该证书发送给客户端,客户端需要验证该证书的身份。客户端找到第三方机构 CA,获知 CA 的公钥,并用 CA 公钥对证书的签名进行解密,获得了 CA 生成的摘要。

客户端对证书数据(包含服务器的公钥)做相同的散列处理,得到摘要,并将该摘要与之前从签名中解码出的摘要做对比,如果相同,则身份验证成功;否则验证失败。

总结来说,带有证书的公钥传输机制如下:

  1. 设有服务器 S,客户端 C,和第三方信赖机构 CA。
  2. S 信任 CA,CA 是知道 S 公钥的,CA 向 S 颁发证书。并附上 CA 私钥对消息摘要的加密签名。
  3. S 获得 CA 颁发的证书,将该证书传递给 C。
  4. C 获得 S 的证书,信任 CA 并知晓 CA 公钥,使用 CA 公钥对 S 证书上的签名解密,同时对消息进行散列处理,得到摘要。比较摘要,验证 S 证书的真实性。
  5. 如果 C 验证 S 证书是真实的,则信任 S 的公钥(在 S 证书中)。

对于数字签名,我这里讲的比较简单,如果你没有搞清楚的话,强烈推荐你看看数字签名及数字证书原理这个视频,这是我看过最清晰的讲解。

  • 端口号:HTTP 默认是 80,HTTPS 默认是 443。
  • URL 前缀:HTTP 的 URL 前缀是 ,HTTPS 的 URL 前缀是 。
  • 安全性和资源消耗:HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 运行在 TCP 之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。
JavaGuide 官方公众号
JavaGuide 官方公众号

这篇文章会从下面几个维度来对比 HTTP 1.0 和 HTTP 1.1:

  • 响应状态码
  • 缓存处理
  • 连接方式
  • Host 头处理
  • 带宽优化

HTTP/1.0 仅定义了 16 种状态码。HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,——在请求大资源前的预热请求,——范围请求的标识码,——请求与当前资源的规定冲突,——资源已被永久转移,而且没有任何已知的转发地址。

缓存技术通过避免用户与源服务器的频繁交互,节约了大量的网络带宽,降低了用户接收信息的延迟。

HTTP/1.0 提供的缓存机制非常简单。服务器端使用标签来标志(时间)一个响应体,在标志时间内的请求,都会获得该响应体缓存。服务器端在初次返回给客户端的响应体中,有一个标签,该标签标记了被请求资源在服务器端的最后一次修改。在请求头中,使用标签,该标签标志一个时间,意为客户端向服务器进行问询:“该时间之后,我要请求的资源是否有被修改过?”通常情况下,请求头中的的值即为上一次获得该资源时,响应体中的的值。

如果服务器接收到了请求头,并判断时间后,资源确实没有修改过,则返回给客户端一个响应头,表示”缓冲可用,你从浏览器里拿吧!”。

如果服务器判断时间后,资源被修改过,则返回给客户端一个的响应体,并附带全新的资源内容,表示”你要的我已经改过的,给你一份新的”。

HTTP1.0cache1
HTTP1.0cache1
HTTP1.0cache2
HTTP1.0cache2

HTTP/1.1 的缓存机制在 HTTP/1.0 的基础上,大大增加了灵活性和扩展性。基本工作原理和 HTTP/1.0 保持不变,而是增加了更多细致的特性。其中,请求头中最常见的特性就是,详见 MDN Web 文档 Cache-Control.

HTTP/1.0 默认使用短连接 ,也就是说,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个 HTML 或其他类型的 Web 页中包含有其他的 Web 资源(如 JavaScript 文件、图像文件、CSS 文件等),每遇到这样一个 Web 资源,浏览器就会重新建立一个 TCP 连接,这样就会导致有大量的“握手报文”和“挥手报文”占用了带宽。

为了解决 HTTP/1.0 存在的资源浪费的问题, HTTP/1.1 优化为默认长连接模式 。 采用长连接模式的请求报文会通知服务端:“我向你请求连接,并且连接成功建立后,请不要关闭”。因此,该 TCP 连接将持续打开,为后续的客户端-服务端的数据交互服务。也就是说在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。

如果 TCP 连接一直保持的话也是对资源的浪费,因此,一些服务器软件(如 Apache)还会支持超时时间的时间。在超时时间之内没有新的请求达到,TCP 连接才会被关闭。

有必要说明的是,HTTP/1.0 仍提供了长连接选项,即在请求头中加入。同样的,在 HTTP/1.1 中,如果不希望使用长连接选项,也可以在请求头中加入,这样会通知服务器端:“我不需要长连接,连接成功后即可关闭”。

HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。

实现长连接需要客户端和服务端都支持长连接。

域名系统(DNS)允许多个主机名绑定到同一个 IP 地址上,但是 HTTP/1.0 并没有考虑这个问题,假设我们有一个资源 URL 是http://example1.org/home.html,HTTP/1.0 的请求报文中,将会请求的是.也就是不会加入主机名。这样的报文送到服务器端,服务器是理解不了客户端想请求的真正网址。

因此,HTTP/1.1 在请求头中加入了字段。加入字段的报文头部将会是:

这样,服务器端就可以确定客户端想要请求的真正的网址了。

HTTP/1.1 引入了范围请求(range request)机制,以避免带宽的浪费。当客户端想请求一个文件的一部分,或者需要继续下载一个已经下载了部分但被终止的文件,HTTP/1.1 可以在请求中加入头部,以请求(并只能请求字节型数据)数据的一部分。服务器端可以忽略头部,也可以返回若干响应。

状态码的主要作用是确保客户端和代理服务器能正确识别部分内容响应,避免将其误认为完整资源并错误地缓存。这对于正确处理范围请求和缓存管理非常重要。

一个典型的 HTTP/1.1 范围请求示例:

响应:

简单解释一下 HTTP 范围响应头部中的字段:

  • 头部:指示返回数据在整个资源中的位置,包括起始和结束字节以及资源的总长度。例如, 表示服务器端返回了第 0 到 1023 字节的数据(共 1024 字节),而整个资源的总长度是 146,515 字节。
  • 头部:指示此次响应中实际传输的字节数。例如, 表示服务器端传输了 1024 字节的数据。

请求头不仅可以请求单个字节范围,还可以一次性请求多个范围。这种方式被称为“多重范围请求”(multiple range requests)。

客户端想要获取资源的第 0 到 499 字节以及第 1000 到 1499 字节:

服务器端返回多个字节范围,每个范围的内容以分隔符分开:

HTTP/1.1 中新加入了状态码。该状态码的使用场景为,存在某些较大的文件请求,服务器可能不愿意响应这种请求,此时状态码可以作为指示请求是否会被正常响应,过程如下图:

HTTP1.1continue1
HTTP1.1continue1
HTTP1.1continue2
HTTP1.1continue2

然而在 HTTP/1.0 中,并没有状态码,要想触发这一机制,可以发送一个头部,其中包含一个的值。

许多格式的数据在传输时都会做预压缩处理。数据的压缩可以大幅优化带宽的利用。然而,HTTP/1.0 对数据压缩的选项提供的不多,不支持压缩细节的选择,也无法区分端到端(end-to-end)压缩或者是逐跳(hop-by-hop)压缩。

HTTP/1.1 则对内容编码(content-codings)和传输编码(transfer-codings)做了区分。内容编码总是端到端的,传输编码总是逐跳的。

HTTP/1.0 包含了头部,对消息进行端到端编码。HTTP/1.1 加入了头部,可以对消息进行逐跳传输编码。HTTP/1.1 还加入了头部,是客户端用来指示他能处理什么样的内容编码。

  1. 连接方式 : HTTP 1.0 为短连接,HTTP 1.1 支持长连接。
  2. 状态响应码 : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,——在请求大资源前的预热请求,——范围请求的标识码,——请求与当前资源的规定冲突,——资源已被永久转移,而且没有任何已知的转发地址。
  3. 缓存处理 : 在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
  4. 带宽优化及网络连接的使用 :HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  5. Host 头处理 : HTTP/1.1 在请求头中加入了字段。

Key differences between HTTP/1.0 and HTTP/1.1

JavaGuide 官方公众号
JavaGuide 官方公众号

HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被成功处理。

常见 HTTP 状态码
常见 HTTP 状态码

相比于其他类别状态码来说,1xx 你平时你大概率不会碰到,所以这里直接跳过。

  • 200 OK:请求被成功处理。例如,发送一个查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。这个是我们平时最常见的一个 HTTP 状态码。
  • 201 Created:请求被成功处理并且在服务端创建了一个新的资源。例如,通过 POST 请求创建一个新的用户。
  • 202 Accepted:服务端已经接收到了请求,但是还未处理。例如,发送一个需要服务端花费较长时间处理的请求(如报告生成、Excel 导出),服务端接收了请求但尚未处理完毕。
  • 204 No Content:服务端已经成功处理了请求,但是没有返回任何内容。例如,发送请求删除一个用户,服务器成功处理了删除操作但没有返回任何内容。

🐛 修正(参见:issue#2458):201 Created 状态码更准确点来说是创建一个或多个新的资源,可以参考:https://httpwg.org/specs/rfc9110.html#status.201。

这里格外提一下 204 状态码,平时学习/工作中见到的次数并不多。

HTTP RFC 2616 对 204 状态码的描述如下:

简单来说,204 状态码描述的是我们向服务端发送 HTTP 请求之后,只关注处理结果是否成功的场景。也就是说我们需要的就是一个结果:true/false。

举个例子:你要追一个女孩子,你问女孩子:“我能追你吗?”,女孩子回答:“好!”。我们把这个女孩子当做是服务端就很好理解 204 状态码了。

  • 301 Moved Permanently:资源被永久重定向了。比如你的网站的网址更换了。
  • 302 Found:资源被临时重定向了。比如你的网站的某些资源被暂时转移到另外一个网址。
  • 400 Bad Request:发送的 HTTP 请求存在问题。比如请求参数不合法、请求方法错误。
  • 401 Unauthorized:未认证却请求需要认证之后才能访问的资源。
  • 403 Forbidden:直接拒绝 HTTP 请求,不处理。一般用来针对非法请求。
  • 404 Not Found:你请求的资源未在服务端找到。比如你请求某个用户的信息,服务端并没有找到指定的用户。
  • 409 Conflict:表示请求的资源与服务端当前的状态存在冲突,请求无法被处理。
  • 500 Internal Server Error:服务端出问题了(通常是服务端出 Bug 了)。比如你服务端处理请求的时候突然抛出异常,但是异常并未在服务端被正确处理。
  • 502 Bad Gateway:我们的网关将请求转发到服务端,但是服务端返回的却是一个错误的响应。
  • https://www.restapitutorial.com/httpstatuscodes.html
  • https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
  • https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
  • https://segmentfault.com/a/64501
JavaGuide 官方公众号
JavaGuide 官方公众号

DNS(Domain Name System)域名管理系统,是当用户使用浏览器访问网址之后,使用的第一个重要协议。DNS 要解决的是域名和 IP 地址的映射问题

DNS:域名系统
DNS:域名系统

在实际使用中,有一种情况下,浏览器是可以不必动用 DNS 就可以获知域名和 IP 地址的映射的。浏览器在本地会维护一个列表,一般来说浏览器要先查看要访问的域名是否在列表中,如果有的话,直接提取对应的 IP 地址记录,就好了。如果本地列表内没有域名-IP 对应记录的话,那么 DNS 就闪亮登场了。

目前 DNS 的设计采用的是分布式、层次数据库结构,DNS 是应用层协议,基于 UDP 协议之上,端口为 53

TCP/IP 各层协议概览
TCP/IP 各层协议概览

DNS 服务器自底向上可以依次分为以下几个层级(所有 DNS 服务器都属于以下四个类别之一):

  • 根 DNS 服务器。根 DNS 服务器提供 TLD 服务器的 IP 地址。目前世界上只有 13 组根服务器,我国境内目前仍没有根服务器。
  • 顶级域 DNS 服务器(TLD 服务器)。顶级域是指域名的后缀,如、、和等。国家也有自己的顶级域,如、和。TLD 服务器提供了权威 DNS 服务器的 IP 地址。
  • 权威 DNS 服务器。在因特网上具有公共可访问主机的每个组织机构必须提供公共可访问的 DNS 记录,这些记录将这些主机的名字映射为 IP 地址。
  • 本地 DNS 服务器。每个 ISP(互联网服务提供商)都有一个自己的本地 DNS 服务器。当主机发出 DNS 请求时,该请求被发往本地 DNS 服务器,它起着代理的作用,并将该请求转发到 DNS 层次结构中。严格说来,不属于 DNS 层级结构。

世界上并不是只有 13 台根服务器,这是很多人普遍的误解,网上很多文章也是这么写的。实际上,现在根服务器数量远远超过这个数量。最初确实是为 DNS 根服务器分配了 13 个 IP 地址,每个 IP 地址对应一个不同的根 DNS 服务器。然而,由于互联网的快速发展和增长,这个原始的架构变得不太适应当前的需求。为了提高 DNS 的可靠性、安全性和性能,目前这 13 个 IP 地址中的每一个都有多个服务器,截止到 2023 年底,所有根服务器之和达到了 600 多台,未来还会继续增加。

以下图为例,介绍 DNS 的查询解析过程。DNS 的查询解析过程分为两种模式:

  • 迭代
  • 递归

下图是实践中常采用的方式,从请求主机到本地 DNS 服务器的查询是递归的,其余的查询时迭代的。

现在,主机想知道的 IP 地址。假设主机的本地 DNS 服务器为,并且的权威 DNS 服务器为。

  1. 首先,主机向本地 DNS 服务器发送一个 DNS 请求,该查询报文包含被转换的域名。
  2. 本地 DNS 服务器检查本机缓存,发现并无记录,也不知道的 IP 地址该在何处,不得不向根服务器发送请求。
  3. 根服务器注意到请求报文中含有顶级域,因此告诉本地 DNS,你可以向的 TLD DNS 发送请求,因为目标域名的 IP 地址很可能在那里。
  4. 本地 DNS 获取到了的 TLD DNS 服务器地址,向其发送请求,询问的 IP 地址。
  5. 的 TLD DNS 服务器仍不清楚请求域名的 IP 地址,但是它注意到该域名有前缀,因此返回告知本地 DNS,的权威服务器可能记录了目标域名的 IP 地址。
  6. 这一次,本地 DNS 将请求发送给权威 DNS 服务器。
  7. 终于,由于向权威 DNS 服务器备案过,在这里有它的 IP 地址记录,权威 DNS 成功地将 IP 地址返回给本地 DNS。
  8. 最后,本地 DNS 获取到了目标域名的 IP 地址,将其返回给请求主机。

除了迭代式查询,还有一种递归式查询如下图,具体过程和上述类似,只是顺序有所不同。

另外,DNS 的缓存位于本地 DNS 服务器。由于全世界的根服务器甚少,只有 600 多台,分为 13 组,且顶级域的数量也在一个可数的范围内,因此本地 DNS 通常已经缓存了很多 TLD DNS 服务器,所以在实际查找过程中,无需访问根服务器。根服务器通常是被跳过的,不请求的。这样可以提高 DNS 查询的效率和速度,减少对根服务器和 TLD 服务器的负担。

DNS 的报文格式如下图所示:

DNS 报文分为查询和回答报文,两种形式的报文结构相同。

  • 标识符。16 比特,用于标识该查询。这个标识符会被复制到对查询的回答报文中,以便让客户用它来匹配发送的请求和接收到的回答。
  • 标志。1 比特的”查询/回答“标识位,表示查询报文,表示回答报文;1 比特的”权威的“标志位(当某 DNS 服务器是所请求名字的权威 DNS 服务器时,且是回答报文,使用”权威的“标志);1 比特的”希望递归“标志位,显式地要求执行递归查询;1 比特的”递归可用“标志位,用于回答报文中,表示 DNS 服务器支持递归查询。
  • 问题数、回答 RR 数、权威 RR 数、附加 RR 数。分别指示了后面 4 类数据区域出现的数量。
  • 问题区域。包含正在被查询的主机名字,以及正被询问的问题类型。
  • 回答区域。包含了对最初请求的名字的资源记录。在回答报文的回答区域中可以包含多条 RR,因此一个主机名能够有多个 IP 地址。
  • 权威区域。包含了其他权威服务器的记录。
  • 附加区域。包含了其他有帮助的记录。

DNS 服务器在响应查询时,需要查询自己的数据库,数据库中的条目被称为 资源记录(Resource Record,RR) 。RR 提供了主机名到 IP 地址的映射。RR 是一个包含了, , , 四个字段的四元组。

是该记录的生存时间,它决定了资源记录应当从缓存中删除的时间。

和字段的取值取决于:

  • 如果,则是主机名信息, 是该主机名对应的 IP 地址。这样的 RR 记录了一条主机名到 IP 地址的映射。
  • 如果 (与 记录非常相似),唯一的区别是 A 记录使用的是 IPv4,而 记录使用的是 IPv6。
  • 如果 (Canonical Name Record,真实名称记录) ,则是别名为的主机对应的规范主机名。值才是规范主机名。 记录将一个主机名映射到另一个主机名。 记录用于为现有的 记录创建别名。下文有示例。
  • 如果,则是个域,而是个知道如何获得该域中主机 IP 地址的权威 DNS 服务器的主机名。通常这样的 RR 是由 TLD 服务器发布的。
  • 如果 ,则是个别名为的邮件服务器的规范主机名。既然有了 记录,那么邮件服务器可以和其他服务器使用相同的别名。为了获得邮件服务器的规范主机名,需要请求 记录;为了获得其他服务器的规范主机名,需要请求 记录。

记录总是指向另一则域名,而非 IP 地址。假设有下述 DNS zone:

当用户查询 的时候,DNS Server 实际返回的是 的 IP 地址。

  • DNS 服务器类型:https://www.cloudflare.com/zh-cn/learning/dns/dns-server-types/
  • DNS Message Resource Record Field Formats:http://www.tcpipguide.com/free/t_DNSMessageResourceRecordFieldFormats-2.htm
  • Understanding Different Types of Record in DNS Server:https://www.mustbegeek.com/understanding-different-types-of-record-in-dns-server/
JavaGuide 官方公众号
JavaGuide 官方公众号

为了准确无误地把数据送达目标处,TCP 协议采用了三次握手策略。

TCP 三次握手图解
TCP 三次握手图解

建立一个 TCP 连接需要“三次握手”,缺一不可:

  • 一次握手:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务端的确认;
  • 二次握手:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 SYN_RECV 状态;
  • 三次握手:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务端都进入ESTABLISHED 状态,完成 TCP 三次握手。

当建立了 3 次握手之后,客户端和服务端就可以传输数据啦!

在 TCP 三次握手过程中,Linux 内核会维护两个队列来管理连接请求:

  1. 半连接队列(也称 SYN Queue):当服务端收到客户端的 SYN 请求时,此时双方还没有完全建立连接,它会把半连接状态的连接放在半连接队列。
  2. 全连接队列(也称 Accept Queue):当服务端收到客户端对 ACK 响应时,意味着三次握手成功完成,服务端会将该连接从半连接队列移动到全连接队列。如果未收到客户端的 ACK 响应,会进行重传,重传的等待时间通常是指数增长的。如果重传次数超过系统规定的最大重传次数,系统将从半连接队列中删除该连接信息。

这两个队列的存在是为了处理并发连接请求,确保服务端能够有效地管理新的连接请求。另外,新的连接请求被拒绝或忽略除了和每个队列的大小限制有关系之外,还和很多其他因素有关系,这里就不详细介绍了,整体逻辑比较复杂。

三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。

  1. 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
  2. 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
  3. 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常

三次握手就能确认双方收发功能都正常,缺一不可。

更详细的解答可以看这个:TCP 为什么是三次握手,而不是两次或四次? - 车小胖的回答 - 知乎 。

服务端传回发送端所发送的 ACK 是为了告诉客户端:“我接收到的信息确实就是你所发送的信号了”,这表明从客户端到服务端的通信是正常的。回传 SYN 则是为了建立并确认从服务端到客户端的通信。

SYN 同步序列编号(Synchronize Sequence Numbers) 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务端之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务端使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement)消息响应。这样在客户机和服务端之间才能建立起可靠的 TCP 连接,数据才可以在客户机和服务端之间传递。

在 TCP 三次握手过程中,第三次握手是可以携带数据的(客户端发送完 ACK 确认包之后就进入 ESTABLISHED 状态了),这一点在 RFC 793 文档中有提到。也就是说,一旦完成了前两次握手,TCP 协议允许数据在第三次握手时开始传输。

如果第三次握手的 ACK 确认包丢失,但是客户端已经开始发送携带数据的包,那么服务端在收到这个携带数据的包时,如果该包中包含了 ACK 标记,服务端会将其视为有效的第三次握手确认。这样,连接就被认为是建立的,服务端会处理该数据包,并继续正常的数据传输流程。

TCP 四次挥手图解
TCP 四次挥手图解

断开一个 TCP 连接则需要“四次挥手”,缺一不可:

  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 (ACK=y+1)标志的数据包->服务端,然后客户端进入TIME-WAIT状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。

只要四次挥手没有结束,客户端和服务端就可以继续传输数据!

TCP 是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。

举个例子:A 和 B 打电话,通话即将结束后。

  1. 第一次挥手:A 说“我没啥要说的了”
  2. 第二次挥手:B 回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话
  3. 第三次挥手:于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”
  4. 第四次挥手:A 回答“知道了”,这样通话才算结束。

因为服务端收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务端到客户端的数据传送。

客户端没有收到 ACK 确认,会重新发送 FIN 请求。

第四次挥手时,客户端发送给服务端的 ACK 有可能丢失,如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,如果客户端在 2*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN。

MSL(Maximum Segment Lifetime) : 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。

  • 《计算机网络(第 7 版)》
  • 《图解 HTTP》
  • TCP and UDP Tutorial:https://www.9tut.com/tcp-and-udp-tutorial
  • 从一次线上问题说起,详解 TCP 半连接队列、全连接队列:https://mp.weixin..com/s/YpSlU1yaowTs-pF6R43hMw
JavaGuide 官方公众号
JavaGuide 官方公众号

  1. 基于数据块传输:应用数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
  2. 对失序数据包重新排序以及去重:TCP 为了保证不发生丢包,就给每个包一个序列号,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据就可以实现数据包去重。
  3. 校验和 : TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
  4. 重传机制 : 在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。TCP 重传机制主要有:基于计时器的重传(也就是超时重传)、快速重传(基于接收端的反馈信息来引发重传)、SACK(在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了)、D-SACK(重复 SACK,在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了)。关于重传机制的详细介绍,可以查看详解 TCP 超时与重传机制这篇文章。
  5. 流量控制 : TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议(TCP 利用滑动窗口实现流量控制)。
  6. 拥塞控制 : 当网络拥塞时,减少数据的发送。TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。接收方的接收能力由滑动窗口表示,表示接收方还有多少缓冲区可以用来接收数据。网络的拥塞程度由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞。

TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。

为什么需要流量控制? 这是因为双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来。如果接收方处理不过来的话,就只能把处理不过来的数据存在 接收缓冲区(Receiving Buffers) 里(失序的数据包也会被存放在缓存区里)。如果缓存区满了发送方还在狂发数据的话,接收方只能把收到的数据包丢掉。出现丢包问题的同时又疯狂浪费着珍贵的网络资源。因此,我们需要控制发送方的发送速率,让接收方与发送方处于一种动态平衡才好。

这里需要注意的是(常见误区):

  • 发送端不等同于客户端
  • 接收端不等同于服务端

TCP 为全双工(Full-Duplex, FDX)通信,双方可以进行双向通信,客户端和服务端既可能是发送端又可能是服务端。因此,两端各有一个发送缓冲区与接收缓冲区,两端都各自维护一个发送窗口和一个接收窗口。接收窗口大小取决于应用、系统、硬件的限制(TCP 传输速率不能大于应用的数据处理速率)。通信双方的发送窗口和接收窗口的要求相同

TCP 发送窗口可以划分成四个部分

  1. 已经发送并且确认的 TCP 段(已经发送并确认);
  2. 已经发送但是没有确认的 TCP 段(已经发送未确认);
  3. 未发送但是接收方准备接收的 TCP 段(可以发送);
  4. 未发送并且接收方也并未准备接受的 TCP 段(不可发送)。

TCP 发送窗口结构图示

TCP发送窗口结构
TCP发送窗口结构
  • SND.WND:发送窗口。
  • SND.UNA:Send Unacknowledged 指针,指向发送窗口的第一个字节。
  • SND.NXT:Send Next 指针,指向可用窗口的第一个字节。

可用窗口大小 = 。

TCP 接收窗口可以划分成三个部分

  1. 已经接收并且已经确认的 TCP 段(已经接收并确认);
  2. 等待接收且允许发送方发送 TCP 段(可以接收未确认);
  3. 不可接收且不允许发送方发送 TCP 段(不可接收)。

TCP 接收窗口结构图示

TCP接收窗口结构
TCP接收窗口结构

接收窗口的大小是根据接收端处理数据的速度动态调整的。 如果接收端读取数据快,接收窗口可能会扩大。 否则,它可能会缩小。

另外,这里的滑动窗口大小只是为了演示使用,实际窗口大小通常会远远大于这个值。

在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞。拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点通信量的控制,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便使接收端来得及接收。

TCP的拥塞控制
TCP的拥塞控制

为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。

TCP 的拥塞控制采用了四种算法,即 慢开始拥塞避免快重传快恢复。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。

  • 慢开始: 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd 初始值为 1,每经过一个传播轮次,cwnd 加倍。
  • 拥塞避免: 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送方的 cwnd 加 1.
  • 快重传与快恢复: 在 TCP/IP 中,快速重传和恢复(fast retransmit and recovery,FRR)是一种拥塞控制算法,它能快速恢复丢失的数据包。没有 FRR,如果数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。有了 FRR,如果接收机接收到一个不按顺序的数据段,它会立即给发送机发送一个重复确认。如果发送机接收到三个重复确认,它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。有了 FRR,就不会因为重传时要求的暂停被耽误。  当有单独的数据包丢失时,快速重传和恢复(FRR)能最有效地工作。当有多个数据信息包在某一段很短的时间内丢失时,它则不能很有效地工作。

自动重传请求(Automatic Repeat-reQuest,ARQ)是 OSI 模型中数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认信息(Acknowledgements,就是我们常说的 ACK),它通常会重新发送,直到收到确认或者重试超过一定的次数。

ARQ 包括停止等待 ARQ 协议和连续 ARQ 协议。

停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复 ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组;

在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。

1) 无差错情况:

发送方发送分组,接收方在规定时间内收到,并且回复确认.发送方再次发送。

2) 出现差错情况(超时重传):

停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重传时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为 自动重传请求 ARQ 。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。

3) 确认丢失和确认迟到

  • 确认丢失:确认消息在传输过程丢失。当 A 发送 M1 消息,B 收到后,B 向 A 发送了一个 M1 确认消息,但却在传输过程中丢失。而 A 并不知道,在超时计时过后,A 重传 M1 消息,B 再次收到该消息后采取以下两点措施:1. 丢弃这个重复的 M1 消息,不向上层交付。 2. 向 A 发送确认消息。(不会认为已经发送过了,就不再发送。A 能重传,就证明 B 的确认消息丢失)。
  • 确认迟到:确认消息在传输过程中迟到。A 发送 M1 消息,B 收到并发送确认。在超时时间内没有收到确认消息,A 重传 M1 消息,B 仍然收到并继续发送确认消息(B 收到了 2 份 M1)。此时 A 收到了 B 第二次发送的确认消息。接着发送其他数据。过了一会,A 收到了 B 第一次发送的对 M1 的确认消息(A 也收到了 2 份确认消息)。处理如下:1. A 收到重复的确认后,直接丢弃。2. B 收到重复的 M1 后,也直接丢弃重复的 M1。

连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。

  • 优点: 信道利用率高,容易实现,即使确认丢失,也不必重传。
  • 缺点: 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5 条 消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。

当发送方发送数据之后,它启动一个定时器,等待目的端确认收到这个报文段。接收端实体对已成功收到的包发回一个相应的确认信息(ACK)。如果发送端实体在合理的往返时延(RTT)内未收到确认消息,那么对应的数据包就被假设为已丢失并进行重传。

  • RTT(Round Trip Time):往返时间,也就是数据包从发出去到收到对应 ACK 的时间。
  • RTO(Retransmission Time Out):重传超时时间,即从数据发送时刻算起,超过这个时间便执行重传。

RTO 的确定是一个关键问题,因为它直接影响到 TCP 的性能和效率。如果 RTO 设置得太小,会导致不必要的重传,增加网络负担;如果 RTO 设置得太大,会导致数据传输的延迟,降低吞吐量。因此,RTO 应该根据网络的实际状况,动态地进行调整。

RTT 的值会随着网络的波动而变化,所以 TCP 不能直接使用 RTT 作为 RTO。为了动态地调整 RTO,TCP 协议采用了一些算法,如加权移动平均(EWMA)算法,Karn 算法,Jacobson 算法等,这些算法都是根据往返时延(RTT)的测量和变化来估计 RTO 的值。

  1. 《计算机网络(第 7 版)》
  2. 《图解 HTTP》
  3. https://www.9tut.com/tcp-and-udp-tutorial
  4. https://github.com/wolverinn/Waking-Up/blob/master/Computer%20Network.md
  5. TCP Flow Control—https://www.brianstorti.com/tcp-flow-control/
  6. TCP 流量控制(Flow Control):https://notfalse.net/24/tcp-flow-control
  7. TCP 之滑动窗口原理 : https://cloud.tencent.com/developer/article/
JavaGuide 官方公众号
JavaGuide 官方公众号

每当我们学习一个新的网络协议的时候,都要把他结合到 OSI 七层模型中,或者是 TCP/IP 协议栈中来学习,一是要学习该协议在整个网络协议栈中的位置,二是要学习该协议解决了什么问题,地位如何?三是要学习该协议的工作原理,以及一些更深入的细节。

ARP 协议,可以说是在协议栈中属于一个偏底层的、非常重要的、又非常简单的通信协议。

开始阅读这篇文章之前,你可以先看看下面几个问题:

  1. ARP 协议在协议栈中的位置? ARP 协议在协议栈中的位置非常重要,在理解了它的工作原理之后,也很难说它到底是网络层协议,还是链路层协议,因为它恰恰串联起了网络层和链路层。国外的大部分教程通常将 ARP 协议放在网络层。
  2. ARP 协议解决了什么问题,地位如何? ARP 协议,全称 地址解析协议(Address Resolution Protocol),它解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
  3. ARP 工作原理? 只希望大家记住几个关键词:ARP 表、广播问询、单播响应

在介绍 ARP 协议之前,有必要介绍一下 MAC 地址。

MAC 地址的全称是 媒体访问控制地址(Media Access Control Address)。如果说,互联网中每一个资源都由 IP 地址唯一标识(IP 协议内容),那么一切网络设备都由 MAC 地址唯一标识。

路由器的背面就会注明 MAC 位址
路由器的背面就会注明 MAC 位址

可以理解为,MAC 地址是一个网络设备真正的身份证号,IP 地址只是一种不重复的定位方式(比如说住在某省某市某街道的张三,这种逻辑定位是 IP 地址,他的身份证号才是他的 MAC 地址),也可以理解为 MAC 地址是身份证号,IP 地址是邮政地址。MAC 地址也有一些别称,如 LAN 地址、物理地址、以太网地址等。

还有一点要知道的是,不仅仅是网络资源才有 IP 地址,网络设备也有 IP 地址,比如路由器。但从结构上说,路由器等网络设备的作用是组成一个网络,而且通常是内网,所以它们使用的 IP 地址通常是内网 IP,内网的设备在与内网以外的设备进行通信时,需要用到 NAT 协议。

MAC 地址的长度为 6 字节(48 比特),地址空间大小有 280 万亿之多($2^{48}$),MAC 地址由 IEEE 统一管理与分配,理论上,一个网络设备中的网卡上的 MAC 地址是永久的。不同的网卡生产商从 IEEE 那里购买自己的 MAC 地址空间(MAC 的前 24 比特),也就是前 24 比特由 IEEE 统一管理,保证不会重复。而后 24 比特,由各家生产商自己管理,同样保证生产的两块网卡的 MAC 地址不会重复。

MAC 地址具有可携带性、永久性,身份证号永久地标识一个人的身份,不论他到哪里都不会改变。而 IP 地址不具有这些性质,当一台设备更换了网络,它的 IP 地址也就可能发生改变,也就是它在互联网中的定位发生了变化。

最后,记住,MAC 地址有一个特殊地址:FF-FF-FF-FF-FF-FF(全 1 地址),该地址表示广播地址。

ARP 协议工作时有一个大前提,那就是 ARP 表

在一个局域网内,每个网络设备都自己维护了一个 ARP 表,ARP 表记录了某些其他网络设备的 IP 地址-MAC 地址映射关系,该映射关系以 三元组的形式存储。其中,TTL 为该映射关系的生存周期,典型值为 20 分钟,超过该时间,该条目将被丢弃。

ARP 的工作原理将分两种场景讨论:

  1. 同一局域网内的 MAC 寻址
  2. 从一个局域网到另一个局域网中的网络设备的寻址

假设当前有如下场景:IP 地址为的主机 A,想要给同一局域网内的 IP 地址为主机 B,发送 IP 数据报文。

再次强调,当主机发送 IP 数据报文时(网络层),仅知道目的地的 IP 地址,并不清楚目的地的 MAC 地址,而 ARP 协议就是解决这一问题的。

为了达成这一目标,主机 A 将不得不通过 ARP 协议来获取主机 B 的 MAC 地址,并将 IP 报文封装成链路层帧,发送到下一跳上。在该局域网内,关于此将按照时间顺序,依次发生如下事件:

  1. 主机 A 检索自己的 ARP 表,发现 ARP 表中并无主机 B 的 IP 地址对应的映射条目,也就无从知道主机 B 的 MAC 地址。
  2. 主机 A 将构造一个 ARP 查询分组,并将其广播到所在的局域网中。

    ARP 分组是一种特殊报文,ARP 分组有两类,一种是查询分组,另一种是响应分组,它们具有相同的格式,均包含了发送和接收的 IP 地址、发送和接收的 MAC 地址。当然了,查询分组中,发送的 IP 地址,即为主机 A 的 IP 地址,接收的 IP 地址即为主机 B 的 IP 地址,发送的 MAC 地址也是主机 A 的 MAC 地址,但接收的 MAC 地址绝不会是主机 B 的 MAC 地址(因为这正是我们要问询的!),而是一个特殊值——,之前说过,该 MAC 地址是广播地址,也就是说,查询分组将广播给该局域网内的所有设备。

  3. 主机 A 构造的查询分组将在该局域网内广播,理论上,每一个设备都会收到该分组,并检查查询分组的接收 IP 地址是否为自己的 IP 地址,如果是,说明查询分组已经到达了主机 B,否则,该查询分组对当前设备无效,丢弃之。
  4. 主机 B 收到了查询分组之后,验证是对自己的问询,接着构造一个 ARP 响应分组,该分组的目的地只有一个——主机 A,发送给主机 A。同时,主机 B 提取查询分组中的 IP 地址和 MAC 地址信息,在自己的 ARP 表中构造一条主机 A 的 IP-MAC 映射记录。

    ARP 响应分组具有和 ARP 查询分组相同的构造,不同的是,发送和接受的 IP 地址恰恰相反,发送的 MAC 地址为发送者本身,目标 MAC 地址为查询分组的发送者,也就是说,ARP 响应分组只有一个目的地,而非广播。

  5. 主机 A 终将收到主机 B 的响应分组,提取出该分组中的 IP 地址和 MAC 地址后,构造映射信息,加入到自己的 ARP 表中。

在整个过程中,有几点需要补充说明的是:

  1. 主机 A 想要给主机 B 发送 IP 数据报,如果主机 B 的 IP-MAC 映射信息已经存在于主机 A 的 ARP 表中,那么主机 A 无需广播,只需提取 MAC 地址并构造链路层帧发送即可。
  2. ARP 表中的映射信息是有生存周期的,典型值为 20 分钟。
  3. 目标主机接收到了问询主机构造的问询报文后,将先把问询主机的 IP-MAC 映射存进自己的 ARP 表中,这样才能获取到响应的目标 MAC 地址,顺利的发送响应分组。

总结来说,ARP 协议是一个广播问询,单播响应协议。

更复杂的情况是,发送主机 A 和接收主机 B 不在同一个子网中,假设一个一般场景,两台主机所在的子网由一台路由器联通。这里需要注意的是,一般情况下,我们说网络设备都有一个 IP 地址和一个 MAC 地址,这里说的网络设备,更严谨的说法应该是一个接口。路由器作为互联设备,具有多个接口,每个接口同样也应该具备不重复的 IP 地址和 MAC 地址。因此,在讨论 ARP 表时,路由器的多个接口都各自维护一个 ARP 表,而非一个路由器只维护一个 ARP 表。

接下来,回顾同一子网内的 MAC 寻址,如果主机 A 发送一个广播问询分组,那么 A 所在的子网内所有设备(接口)都将会捕获该分组,因为该分组的目的 IP 与发送主机 A 的 IP 在同一个子网中。但是当目的 IP 与 A 不在同一子网时,A 所在子网内将不会有设备成功接收该分组。那么,主机 A 应该发送怎样的查询分组呢?整个过程按照时间顺序发生的事件如下:

  1. 主机 A 查询 ARP 表,期望寻找到目标路由器的本子网接口的 MAC 地址。

    目标路由器指的是,根据目的主机 B 的 IP 地址,分析出 B 所在的子网,能够把报文转发到 B 所在子网的那个路由器。

  2. 主机 A 未能找到目标路由器的本子网接口的 MAC 地址,将采用 ARP 协议,问询到该 MAC 地址,由于目标接口与主机 A 在同一个子网内,该过程与同一局域网内的 MAC 寻址相同。
  3. 主机 A 获取到目标接口的 MAC 地址,先构造 IP 数据报,其中源 IP 是 A 的 IP 地址,目的 IP 地址是 B 的 IP 地址,再构造链路层帧,其中源 MAC 地址是 A 的 MAC 地址,目的 MAC 地址是本子网内与路由器连接的接口的 MAC 地址。主机 A 将把这个链路层帧,以单播的方式,发送给目标接口。
  4. 目标接口接收到了主机 A 发过来的链路层帧,解析,根据目的 IP 地址,查询转发表,将该 IP 数据报转发到与主机 B 所在子网相连的接口上。

    到此,该帧已经从主机 A 所在的子网,转移到了主机 B 所在的子网了。

  5. 路由器接口查询 ARP 表,期望寻找到主机 B 的 MAC 地址。
  6. 路由器接口如未能找到主机 B 的 MAC 地址,将采用 ARP 协议,广播问询,单播响应,获取到主机 B 的 MAC 地址。
  7. 路由器接口将对 IP 数据报重新封装成链路层帧,目标 MAC 地址为主机 B 的 MAC 地址,单播发送,直到目的地。
JavaGuide 官方公众号
JavaGuide 官方公众号

NAT 协议(Network Address Translation) 的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,Local Area Network,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(Wide Area Network,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 外界通信时,起到了地址转换的关键作用。

NAT 协议
NAT 协议

假设当前场景如上图。中间是一个路由器,它的右侧组织了一个 LAN,网络号为。LAN 侧接口的 IP 地址为,并且该子网内有至少三台主机,分别是,和。路由器的左侧连接的是 WAN,WAN 侧接口的 IP 地址为。

首先,针对以上信息,我们有如下事实需要说明:

  1. 路由器的右侧子网的网络号为,主机号为,三台主机地址,以及路由器的 LAN 侧接口地址,均由 DHCP 协议规定。而且,该 DHCP 运行在路由器内部(路由器自维护一个小 DHCP 服务器),从而为子网内提供 DHCP 服务。
  2. 路由器的 WAN 侧接口地址同样由 DHCP 协议规定,但该地址是路由器从 ISP(网络服务提供商)处获得,也就是该 DHCP 通常运行在路由器所在区域的 DHCP 服务器上。

现在,路由器内部还运行着 NAT 协议,从而为 LAN-WAN 间通信提供地址转换服务。为此,一个很重要的结构是 NAT 转换表。为了说明 NAT 的运行细节,假设有以下请求发生:

  1. 主机向 IP 地址为的 Web 服务器(端口 80)发送了 HTTP 请求(如请求页面)。此时,主机将随机指派一个端口,如,作为本次请求的源端口号,将该请求发送到路由器中(目的地址将是,但会先到达)。
  2. 即路由器的 LAN 接口收到的请求。路由器将为该请求指派一个新的源端口号,如,并将请求报文发送给 WAN 接口。同时,在 NAT 转换表中记录一条转换记录138.76.29.7:5001——10.0.0.1:3345
  3. 请求报文到达 WAN 接口,继续向目的主机发送。

之后,将会有如下响应发生:

  1. 主机收到请求,构造响应报文,并将其发送给目的地。
  2. 响应报文到达路由器的 WAN 接口。路由器查询 NAT 转换表,发现在转换表中有记录,从而将其目的地址和目的端口转换成为,再发送到上。
  3. 被转换的响应报文到达路由器的 LAN 接口,继而被转发至目的地。
LAN-WAN 间通信提供地址转换
LAN-WAN 间通信提供地址转换

🐛 修正(参见:issue#2009):上图第四步的 Dest 值应该为 而不是~~~~,这里笔误了。

针对以上过程,有以下几个重点需要强调:

  1. 当请求报文到达路由器,并被指定了新端口号时,由于端口号有 16 位,因此,通常来说,一个路由器管理的 LAN 中的最大主机数 $≈65500$($2^{16}$ 的地址空间),但通常 SOHO 子网内不会有如此多的主机数量。
  2. 对于目的服务器来说,从来不知道“到底是哪个主机给我发送的请求”,它只知道是来自的路由器转发的请求。因此,可以说,路由器在 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 时代的产物,极大地方便了一些本来棘手的问题,一直被沿用至今。

JavaGuide 官方公众号
JavaGuide 官方公众号

版权声明


相关文章:

  • 武汉电信的ip地址是多少2025-06-07 12:01:03
  • linux shell md52025-06-07 12:01:03
  • 利用树莓派搭建家庭nas简要2025-06-07 12:01:03
  • uvm实战 pdf2025-06-07 12:01:03
  • 计算机硕士就业怎么样2025-06-07 12:01:03
  • makefile strip函数2025-06-07 12:01:03
  • js 注释规范2025-06-07 12:01:03
  • ftp上传工具怎么用2025-06-07 12:01:03
  • 班知达藏文输入法2025-06-07 12:01:03
  • 电驴最新服务器列表 20202025-06-07 12:01:03