本文主要介绍了计算机网络的体系结构和一些重要的协议。文章首先介绍了OSI七层模型和TCP/IP四层模型,并对每一层的功能和常见协议进行了详细说明。接下来,文章讨论了ARP和IP协议,以及与之相关的DHCP、NAT/NAPT等协议。此外,文章还介绍了TCP协议的定义、特点和重传机制,并与UDP进行了比较。最后,文章提到了HTTP、HTTPS、WebSocket等与网络通信相关的协议,并简要介绍了CDN、RPC和HTTPS的工作原理。整体来说,这篇文章对于理解计算机网络的基本知识和常用协议非常有帮助。

体系结构

OSI 七层模型

  • 基本结构
    • 应用层:为用户提供服务,常见协议有 HTTP/HTTPS(80/443)、FTP(21)、SSH(22)、SMTP(25)、POP3(110)、P2P、Telnet、DNS(53)。
    • 表示层:数据处理,编解码、加解密、加解压缩。
    • 会话层:建立、管理、维护应用程序间的对话,常见协议有 RPC。
    • 传输层:为两台主机进程间通信提供通用数据传输服务(建立、管理、维护端到端连接),常见协议有 TCP、UDP。
    • 网络层:路由和(逻辑地址)寻址,常见协议有 IP、ARP、RARP、ICMP(分差错报告报文和询问报文)、IGMP(组播管理)、NAT、OSPF、RIP。
    • 数据链路层:帧编码、检错(CRC)和(物理地址)寻址,常见协议有 Ethernet、IEEE802.3、PPP(点对点协议,使用最多,简单且只检错不纠错,无流量控制且可同时支持多种网络层协议)、ARQ(自动重传请求,包括停止等待 ARQ 和连续 ARQ)。
    • 物理层:比特流传输。
  • 问题
    • 实现过于复杂,效率低。
    • 部分功能在多层重复出现。
    • 制定缺乏实际经验,制定时间周期过长。

TCP/IP 四层模型

  • 应用层:对应 OSI 模型应用层、表示层、会话层,传输单位是报文/消息,工作在用户态,其余三层都工作在内核态。
  • 传输层:对应 OSI 模型传输层,由于传输层的报文中会携带端口号,因此接收方可以识别出该报文是发送给哪个应用,传输单位是段。
  • 网络层:对应 OSI 模型网络层,传输单位是包。
  • 网络接口层:对应 OSI 模型数据链路层、物理层,为网络层提供「链路级别」传输的服务,使用 MAC 地址来标识网络上的设备,传输单位是帧。

ARP

  • MAC 地址:以太网地址或物理地址,长度 6 字节(48 比特),理论上,一个网络设备中的网卡上的 MAC 地址是永久的,前 24 比特由 IEEE 分配,后面由厂商管理,保证不会重复。同时全 1 地址,即 FF-FF-FF-FF-FF-FF,表示广播地址。
  • MAC 的作用是实现「直连」的两个设备之间通信,而 IP 则负责在「没有直连」的两个网络之间进行通信传输。
  • ARP/RARP:解决的是网络层地址(IP)和链路层地址(MAC)之间的转换问题,每个网络设备都自己维护了一个 ARP 表,以  <IP, MAC, TTL>  三元组的形式存储,TTL 是存活时间,该缓存可减少大量网络通信量。协议可归结为广播问询,单播响应。

IP

IPv4

  • 分类
    • A 类:0 + 【7 位网络号】 + 【24 位主机号】 即范围是 0.0.0.0-127.255.255.255,其中 10.0.0.0-10.255.255.255 是私有 IP 地址,除此之外 127.0.0.1 是环回地址,数据包不会流向网络。
    • B 类:10 + 【14 位网络号】 + 【16 位主机号】 即范围是 128.0.0.0-191.255.255.255,其中 172.16.0.0-172.31.255.255 是私有 IP 地址。
    • C 类:110 + 【21 位网络号】 + 【8 位主机号】 即范围是 192.0.0.0-223.255.255.255,其中 192.168.0.0-192.168.255.255 是私有 IP 地址。
    • D 类:1110 + 【28 位组播地址】
    • E 类:1111 + 【28 位留待后用】
    • 主机号全为 1 指定某个网络下的所有主机,用于广播。
    • 主机号全为 0 表示指向本网,常用于路由表中。
    • 优点:简单明了、选路(基于网络地址)简单。
    • 缺点:缺少层次划分,如 B 类下无法进一步方便划分生产、开发和测试环境;C 类包含的主机数量过少,而 B 类又过多,无法很好地同现实匹配。
  • CIDR:无类域间路由选择,消除了传统的 A 类、B 类和 C 类地址以及划分子网的概念,并使用各种长度的网络前缀来代替分类地址中的网络号和子网号。比如 10.100.122.2/24,意指前 24 位是网络号,后 8 位则是主机号。

分片

  • 以太网最大传输单元(MTU)是 1500 字节。因而 TCP 引入了 MSS(除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度),在 TCP 层分片,防止 IP 某个分片丢失导致整个数据包作废,进而因为某个分片丢失而重传整个 IP 报文的分片。

IPv6

  • 16 字节(128 比特),16 进制表示。
  • 包头包首部长度固定 40 字节,自动分配 IP 地址,提高传输性能,也有更多的安全功能。同时去除了分片/重新组装相关字段,只允许在源与目标主机分片重组,提高了中间路由的传输效率。

部分相关协议

  • DHCP:动态获取 IP 地址
    • DHCP 客户端进程监听的是 68 端口号,DHCP 服务端进程监听的是 67 端口号。
    • UDP 广播通信。
  • NAT/NAPT:网络地址(与端口)转换
    • 如将 192.168.1.10 和 192.168.1.11 两个私有地址都转换为公有地址 120.229.175.121,以不同端口号加以区分,进而实现同时和服务端通信。
    • 依赖转换表:性能开销、NAT 设备重启后所有 TCP 连接将被重置。
      • 解决方案:NAT 穿透技术,客户端自己请求 NAT 设备,并自行维护映射条目。

TCP

定义

  • TCP:面向连接的、可靠的、基于字节流的传输层通信协议。
    • 面向连接:一对一才能连接,不能一个主机同时对多个主机发送消息。
    • 可靠:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定到达接收端。
      • TCP 的可靠性是传输层可靠性,也即仅保证数据从 A 传输层可靠发送至 B 传输层,传输层到应用层这部分,并不是 TCP 保证。
      • 在二者间引入服务器,也有保证应用层可靠性的作用。
        • 除此之外,也可以减少连接建立数,消耗更少资源。
        • 便于鉴权校验,提高安全性。
        • 软件版本问题,借助服务器强制部分过低版本升级,否则不能正常使用,同时加入兼容逻辑,解决大部分兼容问题。
    • 基于字节流:一个 TCP 报文不能被对应为一个消息,消息可能会被操作系统分组成多个的 TCP 报文。
      • TCP 粘包:不知道一个用户消息的边界。
        • 固定长度消息:规定用户消息长度,灵活性太低,很少使用。
        • 特殊字符作为边界:两个用户消息中间插入特殊字符串,如 HTTP 通过设置回车符、换行符作为边界。除此之外 HTTP 还有 Content-Length 字段说明数据长度,进一步解决粘包问题。
        • 自定义消息结构:加入说明数据长度的字段。
  • TCP 头部
    • 序列号(32 位):建立连接时通过时钟周期随机生成,SYN 包发向另一方,每发送一次数据,就「累加」一次该「数据字节数」的大小,SYN 和 FIN 包被认为累加 1,其余累加字节数,用来解决网络包乱序问题。
    • 确认应答号(32 位):指下一次「期望」收到的数据的序列号,用来解决丢包的问题。

和 UDP 区别

  • UDP:无连接的、不可靠的、基于数据报的传输层通信协议。头部仅 8 个字节(源端口号、目的端口号、包长度、校验和)。
  • 连接:TCP 面向连接,传输前要先建立连接,UDP 即刻传输数据。
  • 服务对象:TCP 只能一对一服务,UDP 支持一对一、一对多、多对多的交互通信。
  • 可靠性:TCP 按序可靠交付,UDP 尽最大努力交付,可以基于其实现可靠传输协议,即 QUIC。
  • 基于字节流和数据报:TCP 是基于字节流的,不能像 UDP 一样认为一个报文对应一个消息,消息可能被操作系统分组成多个 TCP 报文传输。
  • 拥塞控制、流量控制:TCP 通过二者保证数据安全传输,UDP 在网络拥堵时依旧正常发送。
  • 首部开销:TCP 至少有 20 字节首部长度(是否使用选项字段),UDP 首部固定 8 字节,因而 UDP 也无需首部长度字段,TCP 中有 4 比特的首部长度字段。
  • 传输方式:TCP 流式传输,无边界但保证顺序,UDP 有边界,但可能丢包和乱序。
  • 分片不同:TCP 在传输层分片和重组(是否大于 MSS),分片丢失只需重传丢失的,UDP 在 IP 层分片(是否大于 MTU)。
  • 应用场景:TCP 注重可靠,UDP 注重实时发送、简单高效。
    • TCP:FTP、HTTP/HTTPS、SMTP、SSH、Telnet
    • UDP:DNS、TFTP(端口 69,简单文件传输协议)、SNMP(简单网络管理协议,161 端口,Trap 消息 162 端口)
  • 二者可以同时使用同一个端口,端口在此仅用于区分同一个主机上不同应用程序的数据包,而 TCP/UDP 数据包可以通过 IP 包头协议号字段区分。

三次握手建立连接

  • 【SYN+client_isn】→【SYN+ACK+(client_isn+1)+server_isn】→【ACK+(server_isn+1)】
  • 第三次握手可携带数据,前两次不可。
  • 查看 TCP 状态命令netstat -napt,UDP 对应参数为 u
  • 三次握手的原因
    • 防止「历史连接」初始化了连接。两次握手则被连接方没有中间状态,旧 SYN 报文到达即进入 Established 状态,造成资源浪费。
    • 同步双方各自的序列号,正常是连接方 SYN→ 接收方 ACK→ 接收方 SYN→ 连接方 ACK,中间两步可以合并,所以是三次握手。序列号保证按序、不重复、不缺失传输数据包。
    • 两次握手还有可能导致被连接方不确定发出的 ACK 报文对方是否收到,只能选择收到 SYN 就主动建立连接,造成资源浪费。
    • 另,若第三次握手(即 ack 报文)丢失,还是可以正常建立连接,被连接方在收到数据报文时有 ACK 标识位和确认号(确认收到第二次握手)。
  • 每次建立连接序列号 ISN 不同:防止收到历史连接的数据包,防止接收到伪造的报文。
    • ISN 基于时钟,每 4 微秒+1,存在回绕现象,4.55 小时循环一次。
    • 引入 TCP 时间戳:便于精确计算 RTT,同时防止 ISN 回绕,时间戳不是递增的,则表示数据包是过期的,丢弃。
  • 第一次握手丢失:重传,1s,2s,4s,8s,16s 后依次重试,再等待 32s,若这总计近 1min 内未收到回复,则断开连接,可以通过对应参数tcp_syn_retries修改重传次数。
  • 第二次握手丢失:连接方重传 SYN(没收到第二次握手中的 ACK),被连接方重传 SYN+ACK。
  • 第三次握手丢失:被连接方重传 SYN+ACK。
  • 被连接方收到 SYN(第一次握手)后创建半连接对象,加入「半连接队列」(哈希表实现),收到 ACK(第三次握手)后从「半连接队列」中取出一个对象,创建新的连接对象加入「 Accept 队列」(链表实现),等待应用通过accept()取出连接对象。
  • 服务端如果只bind()了 IP 地址和端口,而没有调用listen(),然后客户端对服务端发起 SYN 报文,服务端回送 RST 报文。
  • SYN 泛洪攻击:打满半连接队列,导致后续正常 SYN 报文都被丢弃,无法正常建立连接。
    • 调大半连接队列大小,调大保存暂时来不及处理数据包队列大小。
    • 减少 SYN+ACK(第二次握手)重传次数
    • 开启 syncookies,收到 SYN 包后计算 cookie,并放到第二次握手报文中,第三次握手检查合法性,合法直接放到「 Accept 队列」。0 值关闭,1 值表示仅半连接队列满时启用,2 值无条件开启。
    • cookie 方案的缺陷:编码解码消耗 CPU 资源,如果攻击者构造大量 ACK 包(第三次握手),则服务端需要大量编码解码,容易耗尽 CPU 资源而无法响应正式请求。同时如果第二次握手丢失,也不会重发第二次握手的信息。
  • 客户端在第二次握手connect成功,服务端accept成功返回是在第三次握手成功之后,没有accept也能顺利建立连接,其主要从全连接队列中拿出一条连接。

四次挥手断开连接

  • 【断连方 FIN,进入 FIN_WAIT_1】→【被断连方 ACK,进入 CLOSED_WAIT】→【被断连方 FIN,进入 LAST_ACK】→【断连方 ACK,进入 TIME_WAIT,停留 2MSL】→【被断连方收到 ACK 后关闭连接,断连方 2MSL 结束后断连】
  • 四次原因:被断连方通常还有数据未处理发送,因而 ACK 和 FIN 一般分开发送。
  • 第一次挥手丢失/第二次挥手丢失:均为断连方重传 FIN,ACK 报文不重传。
  • 第三次挥手丢失:被断连方重传 FIN,FIN_WAIT_2 时长到达阈值后断连方断开连接。
  • 第四次挥手丢失:被断连方重传 FIN,断连方收到 FIN 则重置 2MSL 定时器。
  • 2MSL(报文最大生存时间)原因:发送方数据包到达接收方处理,接收方处理后发送响应,一来一回需要等待 2 倍时间,Linux 系统默认 2MSL 是 60 秒。
    • 2MSL 足以让历史报文都被丢弃,避免新建立相同四元组连接接收到历史数据包。
    • 确保最后的 ACK(第四次挥手)能够被被断连方接收到,若直接关闭则被断连方没收到 ACK 会重发 FIN,发现断连方已断开连接,收到 RST 报文,RST 报文被解释为错误,不是优雅终结方式。
  • TIME_WAIT 过多:如果是客户端,可能导致端口资源受限,而客户端和服务端均可能占用系统资源,比如文件描述符、内存资源、CPU 资源等。
  • 如果服务端要避免过多的 TIME_WAIT 状态的连接,就永远不要主动断开连接,让客户端去断开,由分布在各处的客户端去承受 TIME_WAIT。
  • TCP 的 keepalive:保活机制,类似心跳机制,默认检测时间 7875 秒,也就是至少 7875 秒后才可以发现一个「死亡」连接,较长。
  • 收到 RST 报文:直接关闭,不走四次挥手流程。
  • 调用closeshutdown发起 FIN 报文。
    • 前者完全断开连接,发起方不能接收和发送数据,成为「孤儿连接」,不够优雅。
    • 后者可以允许只关闭写和读中一个方向上的连接。
  • 双方同时断开连接,均认为自己是主动方,各自收到对方 ACK 后进入 TIME_WAIT,等待 2MSL 后连接关闭。
  • ACK 延迟确认机制:没有响应数据要发送时,ACK 会延迟一段时间,若数据报文到达,则会立即发送 ACK。因而四次挥手中的二三次也可能合并(并非只有在没有数据要发送的时候),变成三次挥手。

重传机制

  • 超时重传
    • 往返时延 RTT:数据发送时刻到接收到确认的时刻的差值。
    • 超时重传时间 RTO 应略大于 RTT,过大则效率低,丢失很久才重发,而过小则可能导致未丢失就重发,增大网络负担。
    • RTT 动态变化,因而每次超时重传都把 RTO 设置为原先的两倍,多次超时说明网络环境差,暂时避免重复尝试发送。
  • 快速重传:解决超时重传周期较长的问题。
    • 收到三个相同的 ACK 报文时,会直接重传原先丢失的报文。
    • 存在问题:无法确定究竟重传哪部分报文。
      • 如果只重传丢失的那一个报文,可能后面的连续两个也丢失了,仍需要依次触发三次 ACK,效率太低。
      • 如果全部重传,那未丢失的部分已经顺利接收,浪费资源。
  • SACK 方法(选择性确认)
    • TCP 头部「选项」字段加入SACK,接收方可以把收到的数据告知发送方,实现只重传丢失的数据。
  • D-SACK(重复选择性确认)
    • 告诉发送方,哪些数据被重复接收了,减少资源浪费,确认丢包的是数据还是接收方回应的 ACK。
    • 案例场景
      • 接收方 ACK 丢包。
      • 网络延时,后续数据包顺利到达,触发了快速重传。

滑动窗口

  • 原因:发送数据和回送确认的往返降低了通信效率,窗口大小即无需等待确认应答,而可以继续发送数据的最大值。
  • 通常窗口的大小是由接收方的窗口大小来决定的。
  • 接收方和发送方的窗口大小并不一定相等,随数据读取动态变化,而传输存在时延。

流量控制

  • 原因:避免接收方无法及时处理,发送方不断触发重发机制,浪费网络资源。
  • 同时减少缓存又收缩窗口可能会出现丢包现象,因而采用先收缩窗口,稍后再减少缓存的方式。
    • 缓存的作用:数据包不能立刻从内存中删除,在重传的时候可能会用到。
  • 窗口关闭潜在风险:后续通报窗口非零大小 ACK 报文丢失,则发送方一直等待窗口非零大小 ACK,接收方一直等待数据。
    • 死锁解决:TCP 连接一方收到零窗口通知,就启动计时器,超时则发送窗口探测报文。
  • 糊涂窗口综合征:接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节。
    • 接收方不通告小窗口给发送方
    • 发送方避免发送小数据
      • Nagle 算法,延时处理,满足一个条件才可发送
        • 要等到窗口大小 >= MSS  并且 数据大小 >= MSS
        • 收到之前发送数据的 ACK 回包。
    • 同时满足上面两个条件才能避免糊涂窗口综合征。

拥塞控制

  • 原因:避免发送方的数据填满整个网络。
  • 拥塞判断:发送方没有在规定时间内接收到 ACK 应答报文,即触发了超时重传。
  • 控制算法
    • 慢启动
      • 每收到一个 ACK,拥塞窗口大小+1,呈现指数型增长。
      • 慢启动门限 ssthresh,超过则进入拥塞避免。
    • 拥塞避免
      • 每收到一个 ACK,拥塞窗口大小增加 1/拥塞窗口大小,即线性增长。
    • 拥塞发生
      • 超时重传
        • 慢启动门限设置为拥塞窗口大小一半。
        • 拥塞窗口大小重置为初始化值。
        • 缺陷:反应过于强烈,可能造成网络卡顿。
      • 快速重传
        • 接收方发现丢了中间包,发送三次前一个包的 ACK,不必等待超时重传。
        • 慢启动门限设置为拥塞窗口大小一半。
        • 拥塞窗口大小减半,而非重置为初始化值。
    • 快速恢复
      • 通常和快速恢复算法同时使用,还能收到三次 ACK,说明网络情况不至于需要做出强烈调整。
      • 重传丢失的数据包,若收到重复 ACK,则拥塞窗口大小增加 1。
      • 收到新数据 ACK,将拥塞窗口大小设置为慢启动门限值,说明恢复过程已经结束,可以进入拥塞避免状态。

关闭 TCP 连接

  • 杀掉进程
    • 客户端杀掉进程,会给服务端发送 FIN 报文,影响范围只有该客户端进程建立的连接,其余进程或客户端和服务端的连接不受影响。
    • 服务端杀掉进程,服务端无法继续提供服务,与之相连的 TCP 连接全部被关闭,影响显著。
  • 伪造 RST 报文
    • 存在问题:序列号不一定正好落入接收的窗口范围内,若被丢弃则无法关闭连接。
    • 伪造 RST 报文需要满足「四元组相同」和「序列号落在窗口内」,窗口可能因为数据传输在频繁变化中,直接伪造相对困难。
    • 解决方案:伪造一个四元组相同的 SYN 报文,拿到合法序列号,再借助此发送 RST 报文。

重启 TCP 服务

  • 重启 TCP 服务进程,出现“Address in use”的报错信息。
    • 即通过服务端发起关闭连接操作,于是服务端作为主动方发起四次挥手,会在 TIME_WAIT 停留 2MSL 时间,因而在执行bind()函数的时候,就会返回对应错误。
    • 解决方案:在调用 bind 前,对 socket 设置 SO_REUSEADDR 属性,不会产生危害,可以帮助更快重启服务端程序。

TCP Fast Open

  • 首次连接后客户端本地缓存服务端第二次握手返回报文中的 Fast Open Cookie。
  • 第二次及之后建立连接,第一次握手 SYN 报文可以携带「应用数据」,若 Cookie 有效则接收数据,因而可减少握手带来的 1 个 RTT 时间消耗。

TCP 缺陷

  • 升级 TCP 的工作难度大,很多新特性需要客户端和服务端同时支持。
  • TCP 建立连接的延迟。由于 TCP 实现在内核,TLS 在应用层实现,所以 TLS 无法加密 TCP 头部,因而 TCP 序列号是明文传输,有安全风险,因而需要三次握手来同步各自生成的序列号,增加安全性。
  • TCP 队头阻塞问题。TCP 面向字节流且保证完整有序,因而前面的 TCP 包丢失了,即使后面的到达了,应用层也无法从内核中读取到这部分数据。
  • 网络变化需要重新建立 TCP 连接。当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接。用户会明显感觉到一刻卡顿,因而重新建立连接成本很高。

QUIC

  • 序列号严格递增,重传的包序列号更大。TCP 重传的序列号一致产生了歧义问题,在计算 RTT 的时候容易偏差,进而影响 RTO 的变化。同时严格递增也可以让 QUIC 支持乱序确认,不会因为丢包而阻塞窗口移动,解决了队头阻塞问题。
  • 两种级别的流量控制
    • Stream 级别的流量控制。每个 Stream 都可以认为是一条 HTTP 请求,每个 Stream 都有各自的滑动窗口,因而可以防止因为单个 Stream 影响整个接收缓冲。
    • Connection 级别的流量控制。限制 Stream 加起来的总字节数,防止发送方发送超过缓冲容量。
  • QUIC 并不与 TLS 分层,而是在内部包含了 TLS,可以携带连接信息和 TLS 信息,在非首次连接时数据包也可以一起发送,进而更快建立连接。
  • QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID 来标记通信的两个端点,只要上下文信息仍然保留,即使 IP 地址发生了变化,原始连接 ID 依旧有效,也可以复用原连接,消除重连的成本。
    • 因此 QUIC 在网络切换的响应速度上优势明显,这对于移动设备非常重要,避免了 TCP 协议超时、中断然后重新创建握手带来的高延迟。

HTTP

基础内容

  • 定义:超文本传输协议。
  • 状态码
    • 204 No Content:成功状态码,但没有 body 数据。
    • 206 Partial Content:成功状态码,应用于 HTTP 分块下载或断点续传,表示 body 数据并不是资源的全部。
    • 301 Moved Permanently:永久重定向,请求资源已经不存在了,需要改新 URL 访问。
    • 302 Found:临时重定向,请求资源还在,暂时需要用另一个 URL 访问。和 301 均会在响应头使用 Location 字段指定后续要跳转的 URL。
    • 304 Not Modified:缓存重定向,告诉对方可以继续使用缓存资源。
      • 协商缓存:
        • Etag 优先级比 Last-Modified 高,Etag 一致的情况下再对比 Last-Modified,避免一些 HTTP 服务器未将文件修改时间纳入哈希范围。
        • Etag 是 HTTP 中一致性最强的缓存机制,Last-Modified 只能精确到秒级,以及某些文件可能定期重新生成,但内容没有实际变化,这些情况都适用 Etag 解决。
        • Etag 性能差,比起简单获取修改时间,Etag 还需要对资源进行哈希计算。
    • 403 Forbidden:禁止访问资源,并非请求出错。
    • 404 Not Found:未找到请求的资源。
    • 501 Not Implemented:请求报文正确,但该请求的功能还不支持。
    • 502 Bad Gateway:服务器工作正常,通常是代理或网关返回的错误码。
    • 503 Service Unavailable:服务器当前暂时无法响应客户端,如资源占用满等情况。
  • GET:安全且幂等,可以做缓存,也可以保存为书签。
  • POST:不安全不幂等的,一般不缓存 POST 请求,不能保存为书签。
  • HTTPS 和 HTTP:HTTPS 建立连接多了 TLS 握手过程。传输内容时候 HTTPS 会加密数据,通常是对称加密。

HTTP1.1

  • 相比 HTTP1.0 的改进:
    • 长连接,无需反复断开建立连接,改善性能开销。
    • 管道传输,默认未打开,只要一个请求发出,不必等待其返回即可发送第二个请求,减少整体响应时间。
  • 性能优化
    • 避免发送:缓存技术。
    • 减少 HTTP 请求次数
      • 减少重定向请求:借助代理服务器。
      • 合并请求:减少了重复发送的 HHTTP 头部,同时每个请求可能是不同的 TCP 连接(HTTP1.1 未使用管道的情况及 HTTP1.1 之前),还能减少 TCP 握手和慢启动过程耗费的时间。
        • 小图合并为大图。
        • 图片编码为 base64,不需要单独发起图片相关请求,直接解码即可。
      • 延迟请求:如只获取用户视野的页面资源,用户滑动页面时再向服务器请求接下来的资源。
    • 减少 HTTP 响应的数据大小
      • 有损压缩:多为图片,Accept 字段中 q 告诉对方期望的资源质量,如 Webp 和 PNG 之间。
      • 无损压缩:多为文本文件、程序可执行文件和源代码,content-encoding 字段指定如 gzip 等压缩算法。

HTTP2

  • 相比 HTTP1.1 的改进:
    • 头部压缩:消除重复部分。
    • 二进制格式:全面采用二进制格式,头信息帧和数据帧,无需明文报文转二进制,增加数据传输效率。
    • 并发传输:引入 Stream,多个 Stream 复用一条 TCP 连接,支持乱序发送,解决 HTTP 队头堵塞的问题,无法解决 TCP 队头堵塞,TCP 基于字节流,需要收到的字节数据完整且连续,同时一旦丢包,所有 HTTP 请求都需要等待这个包重传。
    • 服务器主动推送:服务端不是被动响应,如在客户端请求 HTML 文件时服务端可以主动推送 CSS,减少了消息传递的次数。
  • 一些原有优化措施并不一定再有价值,甚至成为反模式。
    • 多图合并(CSS Sprites/雪碧图),意味着哪怕只要用一张小图,也必须完整加载大图,对任何一张小图修改,也会导致缓存整体失效,样式、脚本等类似的资源也同理。引入多路复用后,HTTP2 反而更适合传输小资源,一个错误的 TCP 包会导致所有流等必须等待这个包重传成功。
    • 合并异步请求,会导致所有请求返回时间都受最慢的那个请求的拖累,整体响应速度下降。

HTTP3

  • 相比 HTTP2 的改进:
    • TCP 队头阻塞。
    • TCP 与 TLS 握手时延迟。
    • 网络迁移时需要重新连接。
  • 实现方案:QUIC

RPC

  • 定义:远程过程调用,本身并非具体协议,而是一种调用方式,调用本地方法一样调用远端服务器暴露方法,屏蔽掉一些网络细节。
  • RPC 主要用于 client/server 架构,而 HTTP 主要用于 browser/server 架构,二者现在也在融合。
  • RPC 可以采用体积更小的 protobuf 或其他序列化协议去保存结构体数据,同时不需要考虑浏览器重定向行为等,所以相比 HTTP1.1 性能略好,常用于公司内部微服务。

WebSocket

  • HTTP1.1 的缺陷:半双工,TCP 是全双工的(即同一时间里,双方都可以主动给对方发送数据),HTTP1.1 只能采用长轮询或不断轮询的方式获取数据,在游戏等需要双方大量数据交互的场景完全不适用。
  • 兼容 WebSocket:浏览器在 TCP 三次握手建立连接后,都统一先使用 HTTP 通信,建立 Websocket 连接则带上特殊请求头,对方回状态码 101(表示切换协议):
Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Key(随机生成base64): T2a6wZlAwhgQNqruZ2YUyg==\r\n
  • 适用场景:服务器和客户端(浏览器)频繁交互。

HTTPS

  • 数字证书相关,略。

CDN

  • 内容分发网络,其获取源站资源的过程即是内容分发,也是其核心价值。
  • 主动分发(PUSH):分发由源站主动发起,将内容从源站推送到各个 CDN 缓存节点,无固定业界标准。适用于网站需要预载大量资源的场景,如淘宝、京东等在双十一前把活动中需要的资源推送到 CDN 缓存节点中,特别常用的资源甚至直接缓存到手机 APP 存储空间或浏览器 LocalStorage 中。
  • 被动回源(PULL):由用户访问所触发全自动、双向透明的资源缓存过程。首次访问 CDN 缓存节点发现自己没有对应资源,就实时从源站获取。首次访问通常较慢(但 CDN 网络质量一般远高于普通用户,因而不一定比用户访问源站慢),不适用大数据量资源的场景,适用于小型站点使用 CDN 服务节点。
  • 通常采用超时被动失效和手工主动失效两种方式结合,管理更新资源。
  • CDN 的应用
    • 加速静态资源,CDN 的初衷和核心价值。
    • 安全防御,源站只对 CDN 提供服务,由 CDN 为外部用户服务,相当于网站堡垒机,对 DDoS 攻击等尤其有效,但不能寄托安全保证在 CDN 上。
    • 协议升级,不少 CDN 提供商都同时对接(代售 CA 的)SSL 证书服务,可以实现源站是 HTTP 协议的,而对外开放的网站是基于 HTTPS 的。同理,可以实现源站到 CDN 是 HTTP/1.x 协议,CDN 提供的外部服务是 HTTP/2 或 HTTP/3 协议、实现源站是基于 IPv4 网络的,CDN 提供的外部服务支持 IPv6 网络,等等。
    • 状态缓存,缓存源站状态,减轻源站压力,在网站状态改变时及时刷新缓存。
    • 修改资源,如提供跨域能力,对源站未压缩的资源自动压缩并修改等。
    • 访问控制,实现 IP 黑/白名单功能等。
    • 注入功能,不修改源站代码的前提下,为源站注入各种功能。

键入网址到网页显示,发生了什么

  1. 解析 URL,生成 HTTP 请求信息(HTTP 数据包)。
  2. DNS 查询(浏览器、操作系统、hosts 文件、本地 DNS 服务器缓存、均未找到再查询)。
  3. 三次握手建立 TCP 连接,TCP 报文生成。
  4. IP 报文生成。
  5. 加上 MAC 头,网卡、交换机、路由器转发。
  6. 互相解析数据包(逐层扒),服务器处理响应请求。
  7. 浏览器渲染页面。
  8. TCP 四次挥手断开连接。