关于tcp:玩转TCP

68次阅读

共计 6002 个字符,预计需要花费 16 分钟才能阅读完成。

前言

最近在拉勾教育学习计算机网络相干常识,明天先来学习下 TCP。

注释

什么是 TCP

TCP(Transport Control Protocol)是一个传输层协定,提供 Host-To-Host 数据的牢靠传输,反对全双工,是一个连贯导向的协定。

TCP 的握手和挥手

TCP 是一个连贯导向的协定,设计有建设连贯(握手)和断开连接(挥手)的过程。

TCP 协定有这样几个基本操作:

  • 一个 Host 被动向另一个 Host 发动连贯,称为 SYN(Synchronization),申请同步;
  • 一个 Host 被动断开申请,称为 FIN(Finish),申请实现;
  • 一个 Host 给另一个 Host 发送数据,称为 PSH(Push),数据推送。

以上 3 种状况,接管方收到数据后,都须要给发送方一个 ACK(Acknowledgement)响应。申请 / 响应的模型是可靠性的要求,如果一个申请没有响应,发送方可能会认为本人须要重发这个申请。

建设连贯的过程(三次握手)

因为要放弃连贯和可靠性束缚,TCP 协定要保障每一条收回的数据必须给返回,返回数据叫作 ACK(也就是响应)。

依照这个思路,你能够看看建设连贯是不是须要 3 次握手:

  1. 客户端发消息给服务端(SYN)
  2. 服务端筹备好进行连贯
  3. 服务端针对客户端的 SYN 给一个 ACK

你能够能会问,到这里不就能够了吗?2 次握手就足够了。但其实不是,因为服务端还没有确定客户端是否筹备好了。比方步骤 3 之后,服务端马上给客户端发送数据,这个时候客户端可能还没有筹备好接收数据。因而还须要减少一个过程。

接下来还会产生以下操作:

  1. 服务端发送一个 SYN 给客户端
  2. 客户端准备就绪
  3. 客户端给服务端发送一个 ACK

你可能会问,下面不是 6 个步骤吗?怎么是 3 次握手呢?上面咱们一起剖析一下其中原因。

步骤 1 是 1 次握手;

步骤 2 是服务端的筹备,不是数据传输,因而不算握手;

步骤 3 和步骤 4,因为是同时产生的,能够合并成一个 SYN-ACK 响应,作为一条数据传递给客户端,因而是第 2 次握手;

步骤 5 不算握手;

步骤 6 是第 3 次握手。

为了不便你了解步骤 3 和步骤 4,这里我画了一张图。能够看到下图中 SYN 和 ACK 被合并了,因而建设连贯一共须要 3 次握手,过程如下图所示:

从下面的例子中,你能够进一步思考 SYN、ACK、PSH 这些常见的标识位(Flag)在传输中如何示意。

一种思路是为 TCP 协定减少协定头。在协定头中取多个位(bit),其中 SYN、ACK、PSH 都占有 1 个位。比方 SYN 位,1 示意 SYN 开启,0 示意敞开。因而,SYN-ACK 就是 SYN 位和 ACK 位都置 1。这种设计,咱们也称为标识(Flag)。

断开连接的过程(4 次挥手)

持续下面的思路,如果断开连接须要几次握手?给你一些提醒,你能够在脑海中这样构思。

  1. 客户端要求断开连接,发送一个断开的申请,这个叫作(FIN)。
  1. 服务端收到申请,而后给客户端一个 ACK,作为 FIN 的响应。
  1. 这里你须要思考一个问题,可不可以像握手那样马上传 FIN 回去?
    其实这个时候服务端不能马上传 FIN,因为断开连接要解决的问题比拟多,比如说服务端可能还有发送进来的音讯没有失去 ACK;也有可能服务端本人有资源要开释。因而断开连接不能像握手那样操作——将两条音讯合并。所以,服务端通过一个期待,确定能够敞开连贯了,再发一条 FIN 给客户端。
  1. 客户端收到服务端的 FIN,同时客户端也可能有本人的事件须要解决完,比方客户端有发送给服务端没有收到 ACK 的申请,客户端本人解决实现后,再给服务端发送一个 ACK。

TIME_WAIT

置信大家都晓得,TCP 被动敞开连贯的那一方会最初进入TIME_WAIT 状态。

其实就是客户端收回确认报文后不是立马开释 TCP 连贯,而是要通过 2MSL(最长报文段寿命的 2 倍时长)后才开释 TCP 连贯。

那么 TIME_WAIT 状态是用来解决或防止什么问题呢?

这里同样是要思考丢包的问题,如果第四次挥手的报文失落,服务端没收到确认 ack 报文就会重发第三次挥手的报文,这样报文一去一回最长工夫就是 2MSL,所以须要等这么长时间来确认服务端的确曾经收到了。

TCP 的粘包和拆包

TCP 是一个传输层协定。TCP 发送数据的时候,往往不会将数据一次性发送,像下图这样:

而是将 数据拆分成很多个局部,而后再一一发送。像下图这样:

同样的,在目的地,TCP 协定又须要一一接收数据。请你思考,TCP 为什么不一次发送完所有的数据?比方咱们要传一个大小为 10M 的文件,对于应用层而言,就是一次传送实现的。而传输层的协定为什么不抉择将这个文件一次发送完呢?

这里有很多起因,比方为了稳定性,一次发送的数据越多,出错的概率越大。再比如说为了效率,网络中有时候存在着并行的门路,拆分数据包就能更好地利用这些并行的门路。再有,比方发送和接收数据的时候,都存在着缓冲区。如下图所示:

缓冲区是在内存中开拓的一块区域,目标是缓冲。因为大量的利用频繁地通过网卡收发数据,这个时候,网卡只能一个一个解决利用的申请。当网卡忙不过来的时候,数据就须要排队,也就是将数据放入缓冲区。如果每个利用都随便发送很大的数据,可能导致其余利用实时性受到毁坏。

总之,方方面面的起因:在传输层封包不能太大。这种限度,往往是以缓冲区大小为单位的。也就是 TCP 协定,会将数据拆分成不超过缓冲区大小的一个个局部。每个局部有一个独特的名词,叫作 TCP 段(TCP Segment)。

在接收数据的时候,一个个 TCP 段又被重组成原来的数据

像这样,数据通过拆分,而后传输,而后在目的地重组,俗称拆包。所以 拆包是将数据拆分成多个 TCP 段传输 。那么粘包是什么呢?有时候,如果发往一个目的地的多个数据太小了,为了避免屡次发送占用资源,TCP 协定有可能将它们合并成一个 TCP 段发送,在目的地再还原成多个数据,这个过程俗称粘包。所以 粘包是将多个数据合并成一个 TCP 段发送

Sequence Number 和 Acknowledgement Number

在 TCP 协定的设计当中,数据被拆分成很多个局部,局部减少了协定头。合并成为一个 TCP 段,进行传输。这个过程,咱们俗称拆包。这些 TCP 段通过简单的网络结构,由底层的 IP 协定,负责传输到目的地,而后再进行重组。

这里请你思考一个问题:稳定性要求数据无损地传输,也就是说拆包取得数据,又须要复原到原来的样子。而在简单的网络环境当中,即使所有的段是程序收回的,也不能保障它们程序达到,因而,收回的每一个 TCP 段都须要有序号。这个序号,就是 Sequence Number(Seq)。

如上图所示。发送数据的时候,为每一个 TCP 段调配一个自增的 Sequence Number。接收数据的时候,尽管失去的是乱序的 TCP 段,然而能够通过 Seq 进行排序。

然而这样又会产生一个新的问题——接管方如果要回复发送方,也须要这个 Seq。而网络的两个终端,去同步一个自增的序号是十分艰难的。因为任何两个网络主体间,工夫都不能做到齐全同步,又没有公共的存储空间,无奈共享数据,更别说实现一个分布式的自增序号了。

其实这个问题的实质就如同两个人在谈话一样,咱们要确保他们说进来的话,和答复之间的程序。因为 TCP 是一个双工的协定,两边可能会同时谈话。所以聪慧的科学家想到了确定一句话的程序,须要两个值去形容——也就是发送的字节数和接管的字节数。

咱们从新定义一下 Seq(如上图所示),对于任何一个接管方,如果晓得了发送者发送某个 TCP 段时,曾经发送了多少字节的数据,那么就能够确定发送者发送数据的程序。

然而这里有一个问题。如果接管方也向发送者发送了数据申请(或者说单方在对话),接管方就不晓得发送者发送的数据到底对应哪一条本人发送的数据了。

因而咱们还须要另一个数据,就是每个 TCP 段发送时,发送方曾经接管了多少数据。用 Acknowledgement Number 示意,上面简写为 ACK。

下图中,终端发送了三条数据,并且接管到四条数据,通过观察,依据接管到的数据中的 Seq 和 ACK,将发送和接管的数据进行排序。

例如上图中,发送方发送了 100 字节的数据,而接管到的(Seq = 0 和 Seq =100)的两个封包,都是针对发送方(Seq = 0)这个封包的。发送 100 个字节,所以接管到的 ACK 刚好是 100。阐明(Seq= 0 和 Seq= 100)这两个封包是针对接管到第 100 个字节数据后,发送回来的。这样就确定了整体的程序。

滑动窗口和流速管制

TCP 作为一个传输层协定,最外围的能力是传输。传输须要保障可靠性,还须要管制流速,这两个外围能力均由滑动窗口提供。

申请 / 响应模型

TCP 中每个发送的申请都须要响应。如果一个申请没有收到响应,发送方就会认为这次发送呈现了故障,会触发重发。

大体的模型,和下图很像。然而如果齐全和下图一样,每一个申请收到响应之后,再发送下一个申请,吞吐量会很低。因为这样的设计,会产生网络的闲暇工夫,说白了,就是节约带宽。带宽没有用满,意味着能够同时发送更多的申请,接管更多的响应。

一种改良的形式,就是让发送方有申请就发送进来,而不是期待响应。通过这样的解决形式,发送的数据连在了一起,响应的数据也连在了一起,吞吐量就晋升了。

然而如果能够同时发送的数据真的十分多呢?比方成千盈百个 TCP 段都须要发送,这个时候带宽可能会有余。

滑动窗口(Sliding Window)

那么这时候就须要咱们的滑动窗口来实现了,如下图:

如上图所示:

  • 深绿色代表曾经收到 ACK 的段
  • 浅绿色代表发送了,然而没有收到 ACK 的段
  • 红色代表没有发送的段
  • 紫色代表临时不能发送的段

上面咱们从新设计一下不同类型封包的程序,将已发送的数据放到最右边,发送中的数据放到两头,未发送的数据放到左边。假如咱们最多同时发送 5 个封包,也就是窗口大小 = 5。窗口中的数据被同时发送进来,而后期待 ACK。如果一个封包 ACK 达到,咱们就将它标记为已接管(深绿色)。

如下图所示,有两个封包的 ACK 达到,因而标记为绿色。

这个时候滑动窗口能够向右滑动,如下图所示:

重传

如果发送过程中,局部数据没能收到 ACK 会怎么呢?这就可能产生重传。

如果产生下图这样的状况,段 4 迟迟没有收到 ACK。

这个时候滑动窗口只能右移一个地位,如下图所示:

在这个过程中,如果起初段 4 重传胜利(接管到 ACK),那么窗口就会持续右移。如果段 4 发送失败,还是没能收到 ACK,那么接管方也会摈弃段 5、段 6、段 7。这样从段 4 开始之后的数据都须要重发。

疾速重传

在 TCP 协定中,如果接管方想抛弃某个段,能够抉择不发 ACK。发送端超时后,会重发这个 TCP 段。而有时候,接管方心愿督促发送方尽快补发某个 TCP 段,这个时候能够应用疾速重传能力。

例如段 1、段 2、段 4 到了,然而段 3 没有到。接管方能够发送屡次段 3 的 ACK。如果发送方收到多个段 3 的 ACK,就会重发段 3。这个机制称为疾速重传。这和超时重发不同,是一种督促的机制。

为了不让发送方误以为段 3 曾经收到了,在疾速重传的状况下,接管方即使收到发来的段 4,仍然会发段 3 的 ACK(不发段 4 的 ACK),直到发送方把段 3 重传。

思考:窗口大小的单位是?

请你思考另一个问题,窗口大小的单位是多少呢?在下面所有的图片中,窗口大小是 TCP 段的数量。实际操作中,每个 TCP 段的大小不同,限度数量会让接管方的缓冲区不好操作,因而实际操作中窗口大小单位是 字节数

思考:滑动窗口是越大越好吗?

援用知乎的答复:

流速管制

发送、接管窗口的大小能够用来管制 TCP 协定的流速。窗口越大,同时能够发送、接管的数据就越多,反对的吞吐量也就越大。当然,窗口越大,如果数据产生谬误,损失也就越大,因为须要重传越多的数据。

总结

为了进步传输速率,TCP 协定抉择将多个段同时发送,为了让这些段不至于被接管方拒绝服务,在发送前,单方要协商好发送的速率。然而咱们不可能齐全确定网速,所以协商的形式,就变成确定窗口大小。

有了窗口,发送方利用滑动窗口算法发送音讯;接管方结构缓冲区接管音讯,并给发送方 ACK。滑动窗口的实现只须要数组和大量的指针即可,是一个十分高效的算法。

那么,当初你能够尝试来答复本讲关联的面试题目:滑动窗口和流速管制是怎么回事

【解析】滑动窗口是 TCP 协定管制可靠性的外围。发送方将数据拆包,变成多个分组。而后将数据放入一个领有滑动窗口的数组,顺次收回,依然遵循先入先出(FIFO)的程序,然而窗口中的分组会一次性发送。窗口中序号最小的分组如果收到 ACK,窗口就会产生滑动;如果最小序号的分组长时间没有收到 ACK,就会触发整个窗口的数据从新发送。

另一方面,在屡次传输中,网络的均匀提早往往是绝对固定的,这样 TCP 协定能够通过单方协商窗口大小管制流速。

TCP 和 UDP

TCP 和 UDP 是明天利用最宽泛的传输层协定,领有最外围的垄断位置。TCP 最外围的价值是提供了可靠性,而 UDP 最外围的价值是灵便,你简直能够用它来做任何事件。例如:HTTP 协定 1.1 和 2.0 都基于 TCP,而到了 HTTP 3.0 就开始用 UDP 了。

UDP 与 TCP 的区别

接下来咱们说说 UDP 和 TCP 的区别。

  1. 目标差别
    首先,这两个协定的目标不同:TCP 协定的外围指标是提供牢靠的网络传输,而 UDP 的指标是在提供报文交换能力根底上尽可能地简化协定轻装上阵。
  1. 可靠性差别
    TCP 外围是要在保障可靠性提供更好的服务。TCP 会有握手的过程,须要建设连贯,保障单方同时在线。而且 TCP 有工夫窗口继续收集无序的数据,直到这一批数据都能够正当地排序组成间断的后果。UDP 并不具备以上这些个性,它只管发送数据封包,而且 UDP 不须要 ACK,这意味着音讯发送进来胜利与否 UDP 是不论的。
  1. 连贯 vs 无连贯
    TCP 是一个面向连贯的协定(Connection-oriented Protocol),传输数据必须先建设连贯。UDP 是一个无连贯协定(Connection-less Protocol),数据随时都能够发送,只提供发送封包(Datagram)的能力。
  1. 流控技术(Flow Control)
    TCP 应用了流控技术来确保发送方不会因为一次发送过多的数据包而使接管方不堪重负。TCP 在发送缓冲区中存储数据,并在接收缓冲区中接收数据。当应用程序准备就绪时,它将从接收缓冲区读取数据。如果接收缓冲区已满,接管方将无奈解决更多数据,并将其抛弃。UDP 没有提供相似的能力。
  1. 传输速度
    UDP 协定简化,封包小,没有连贯、可靠性查看等,因而单纯从传输速度上讲,UDP 更快。
  1. 场景差别
    TCP 每个数据封包都须要确认,因而人造不适应高速数据传输场景,比方观看视频(流媒体利用)、网络游戏(TCP 有提早)等。具体来说,如果网络游戏用 TCP,每个封包都须要确认,可能会造成肯定的提早;再比方音、视频传输天生就容许肯定的丢包率;Ping 和 DNSLookup,这类型的操作只须要一次简略的申请 / 返回,不须要建设连贯,用 UDP 就足够了。

总结

这次的 TCP 就学习到这里。

参考

《计算机网络通关 29 讲》

正文完
 0