diff --git a/blogs/computer_network/TCP 的构成.md b/blogs/computer_network/TCP 的构成.md new file mode 100644 index 0000000..885babf --- /dev/null +++ b/blogs/computer_network/TCP 的构成.md @@ -0,0 +1,70 @@ +--- +TCP 的构成 +--- + +#### 目录 + +1. 前言 +2. 三次握手 +3. 拥塞预防及控制 + +#### 前言 + +因特网有两个核心协议:TCP 和 IP。IP,即因特网协议,负责联网主机之间的路由选择和寻址;TCP,即传输控制协议,负责在不可靠的传输信道之上提供可靠地抽象层。 + +TCP 负责在不可靠的传输信道之上提供可靠的抽象层,向应用层隐藏了大多数网络通信的复杂细节,比如丢包重发、按序发送、拥塞控制及避免、数据完整,等等。采用 TCP 数据流可以确保发送的所有字节能够完整的被接收到,而且到达客户端的顺序也一样。也就是说,TCP 专门为精确传送做了优化,但并未过多顾及时间,这一点也给优化浏览器 Web 性能带来了挑战。 + +HTTP 标准并未规定 TCP 就是唯一的传输协议。如果你愿意,还可以通过 UDP(用户数据报协议)或者其他可用协议来发送 HTTP 消息。但在现实当中,由于 TCP 提供了很多有用的功能,几乎所有 HTTP 流量都是通过 TCP 传送的。 + +#### 三次握手 + +所有 TCP 连接一开始都要经过三次握手。客户端与服务器在交换应用数据之前,必须就起始分组序列号,以及其他一些连接相关的细节达成一致。出于安全考虑,序列号由两端随机生成。 + +![](https://i.loli.net/2019/06/18/5d087dcb28ff059341.png) + +* SYN + + 客户端选择一个随机序列号 x,并发送一个 SYN 分组,其中可能还包括其他 TCP 标志和选项。 + +* SYN ACK + + 服务器给 x 加 1,并选择自己的一个随机序列号 y,追加自己的标志和选项,然后返回响应。 + +* ACK + + 客户端给 x 和 y 加 1 并发送握手期间的最后一个 ACK 分组。 + +三次握手完成后,客户端与服务器之间就可以通信了。客户端可以在发送 ACK 分组之后立即发送数据,而服务器必须等接收到 ACK 分组之后才能发送数据。这个启动通信的过程适用于所有 TCP 连接,因此对所有使用 TCP 的应用具有非常大的性能影响,因为每次传输应用数据之前,都必须经历一次完整的往返。 + +举个例子,如果客户端在纽约,服务器在伦敦,要通过光纤启动一次新的 TCP 连接,光三次握手至少要花 56 ms;向伦敦发送分组需要 28 ms,响应发回纽约又要 28 ms。在此,连接的带宽对时间没有影响,延迟完全取决于客户端和服务器之间的往返时间,这其中主要是纽约到伦敦之间的传输时间。 + +三次握手带来的延迟使得每创建一个新的 TCP 连接都要付出很大代价。而这也决定了提高 TCP 应用性能的关键,在于想办法重用连接。 + +> TCP 快速打开 +> +> 遗憾的是,连接不是想重用就可以重用的。事实上,由于非常短的 TCP 连接在互联网上随处可见,握手阶段已经成为影响网络总延迟的一个重要因素。为解决这个问题,人们正在积极寻找各种方案,其中 TFO(TCP Fast Open,TCP 快速打开)就是这样一种机制,致力于减少新建 TCP 连接带来的性能损失。 +> +> Linux 3.7 及之后的内核已经在客户端和服务器中支持 TFO,因此成为了客户端和服务器操作系统选型的有力候选方案。即使如此,TFO 并不能解决所有问题。它虽然有助于减少三次握手的往返时间,但却只能在某些情况下有效。比如,随同 SYN 分组一起发送的数据净荷有最大尺寸限制、只能发送某些类型的 HTTP 请求,以及由于依赖加密 cookie,只能应用于重复的连接。 + +#### 阻塞预防及控制 + +1984 年初,John Nagle 提到了一个被称为 “拥塞崩溃” 的现象,这个现象会影响节点间带宽容量不对称的任何网络:可能是往返时间超过了所有主机的最大中断间隔,于是相应的主机会在网络中制造越来越多的数据报副本,使得整个网络陷入瘫痪。最终,所有交换节点的缓冲区都将被填满,多出来的分组必须删掉。目前的分组往返时间已经设定为最大值。主机会把每个分组都发送好几次,结果每个分组的某个副本会抵达目标,这就是拥塞崩溃。 + +为了解决这些问题,TCP 加入了很多机制,以便控制双向发送数据的速度,比如流量控制、阻塞控制和拥塞预防机制。 + +##### 流量控制 + +流量控制是一种预防发送端过多向接收端发送数据的机制。否则,接收端可能因为忙碌、负载重或缓冲区既定而无法处理。为实现流量控制,TCP 连接的每一方都要通告自己的接收窗口(rwnd),其中包含能够保存数据的缓冲区空间大小信息。 + +![](https://i.loli.net/2019/06/18/5d0885677bcb877502.png) + +第一次建立连接时,两端都会使用自身系统的默认设置来发送 rwnd。浏览网页通过主要是从服务器向客户端下载数据,因此客户端窗口更可能成为瓶颈。然后,如果是在上传图片或视频,即客户端向服务端传送大量数据时,服务器的接收窗口又可能成为制约因素。 + +不管怎样,如果其中一端跟不上数据传输,那它可以向发送端通告一个较小的窗口。假如窗口为零,则意味着必须由应用层先清空缓冲区,才能再接收剩余数据,这个过程贯穿于每个 TCP 连接的整个生命周期:每个 ACK 分组都会携带相应的最新的 rwnd 值,以便两端动态调整数据流速,使之适应发送端和接收端的容量及处理能力。 + +##### 慢启动 + +尽管 TCP 有了流量控制机制,但网络拥塞崩溃仍然在 1980 年代中后期浮出水面。流量控制确实可以防止发送端向接收端过多发送数据,但却没有机制预防任何一端向潜在网络过多发送数据。换句话说,发送端和接收端在连接建立之初,谁也不知道可用带宽是多少,因此需要一个估算机制,然后还要根据网络中不断变化的条件而动态改变速度。 + +要说明这种动态适应机制的好处,可以想象你在家观看一个大型的流视频。视频服务器会尽最大努力根据你的下行连接提供最高品质信息。而此时,你家里又有人打开一个新连接下载某个软件的升级包。可供视频流使用的下行带宽一下子少了很多,视频服务器必须调整它的发送速度。否则,如果继续保持同样的速度,那么数据很快就会在某个中间的网关越积越多,最终会导致分组被删除,从而降低网络传输效率。 + diff --git a/images/network/Web 性能权威指南/TCP 三次握手.png b/images/network/Web 性能权威指南/TCP 三次握手.png new file mode 100644 index 0000000..efa2245 Binary files /dev/null and b/images/network/Web 性能权威指南/TCP 三次握手.png differ diff --git a/images/network/HTTP/二进制分帧层.png b/images/network/Web 性能权威指南/二进制分帧层.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/二进制分帧层.png rename to images/network/Web 性能权威指南/二进制分帧层.png diff --git a/images/network/HTTP/二进制分帧层首部.png b/images/network/Web 性能权威指南/二进制分帧层首部.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/二进制分帧层首部.png rename to images/network/Web 性能权威指南/二进制分帧层首部.png diff --git a/images/network/HTTP/多向请求与响应.png b/images/network/Web 性能权威指南/多向请求与响应.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/多向请求与响应.png rename to images/network/Web 性能权威指南/多向请求与响应.png diff --git a/images/network/HTTP/头部压缩.png b/images/network/Web 性能权威指南/头部压缩.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/头部压缩.png rename to images/network/Web 性能权威指南/头部压缩.png diff --git a/images/network/HTTP/服务器推送.png b/images/network/Web 性能权威指南/服务器推送.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/服务器推送.png rename to images/network/Web 性能权威指南/服务器推送.png diff --git a/images/network/HTTP/流、消息、帧.png b/images/network/Web 性能权威指南/流、消息、帧.png old mode 100755 new mode 100644 similarity index 100% rename from images/network/HTTP/流、消息、帧.png rename to images/network/Web 性能权威指南/流、消息、帧.png diff --git a/images/network/Web 性能权威指南/通告接收窗口大小.png b/images/network/Web 性能权威指南/通告接收窗口大小.png new file mode 100644 index 0000000..067fd7d Binary files /dev/null and b/images/network/Web 性能权威指南/通告接收窗口大小.png differ