传输控制协议(transmission control protocol)——TCP 整理

TCP服务

1、TCP使用端口号来实现进程间通信

2、TCP 是一个面向流的协议。TCP 允许发送进程以字节流形式传递数据,并且接收进程也以字节流形式接收数
据。

3、因为发送和接收进程可能以不同的速度写入和读出数据,所以 TCP 需要用于存储的缓冲区。每一个方向都存在一个缓冲区:发送缓冲区和接收缓冲区。实现缓冲区的一种方法是使用以一字节为存储单元的循环数组

      在发送端,缓冲区有三种类型的存储单元。白色的部分是空存储单元,可以由发送进程(生产者)填充。蓝色的部分用于保存已经发送但还没有得到确认的字节。TCP 在缓冲区中保留这些字节,直到收到确认为止。灰色缓冲区是将要由 TCP 发送
的字节。灰色存储单元的字节被确认后,这些存储单元可以回收并且对发送进程可用。

     接收端的缓冲区操作比较简单。环形缓冲区分成两个区域(表示为白色和蓝色)。白色区域包含空存储单元,可以由从网络上接收的字节进行填充。蓝色区域表示接收到的字节,可以由接收进程读出。当某个字节被接收进程读出以后,这个存储单元可被回收,并加入到空存储单元池中。

4、——IP 层作为 TCP 服务的提供者,需要以分组的方式而不是字节流的方式发送数据。、

     在传输层,TCP 将多个字节组合在一起成为一个分组,这个分组称为段(segment)。TCP 给每个段添加头部(为了达到控制目的),并将该段传递给 IP 层。段被封装到 IP 数据报中,然后再进行传输。整个操作对接收进程是透明的。稍后,我们会看到这些段可能被无序接收、丢失,或者损坏和重发。所有这些均由 TCP 处理,接收进程不会察觉到任何操作。

注意,段的大小不必相同。

5、全双工通信——TCP 提供全双工服务(full-dupler service),即数据可以在同一时间双向流动。每一方向 TCP都有发送和接收缓冲区,它们能在双向发送和接收段。

6、多路复用和多路分解——与 UDP 不同,TCP 在发送端执行多路复用,在接收端执行多路分解。然而,由于 TCP 是一个面向连接协议,因此需要为每对进程建立连接。

(我记得一个进程可以开多个socket,这个就为多路复用和多路分解提供了可能。因为:多路复用就是从源主机的不同套接字中收集数据块,并为每个数据块封装上首部信息从而生成报文段,然后将报文段传递到网络层中去。参考链接:https://blog.csdn.net/ljianhui/article/details/21660629)。

7、面向连接的服务——TCP 段封装成 IP 数据段,并且可能被无序地发送,或丢失,或被破坏,然后重发。每个段都可以通过不同的路径到达目的端。TCP 建立一种面向字节流的环境,在这种环境中,TCP 能承担按顺序传递这些字节到其他站点的任务。

 

 


TCP的特点

1、序号系统——虽然 TCP 软件能够记录发送或接收的段,但是在段的头部没有段序号字段。TCP 在段的头部
采用称为序号(sequence number)确认号(acknowledgment number)的两个字段。这两个字段指的是字节序号(而不是段序号。

2、字节序号——TCP 为在一个连接中传输的所有数据字节(八位字节)编号。在每个方向上序号都是独立的
当 TCP 接收来自进程的一些数据字节时,TCP 将它们存储在发送缓冲区中并给它们编号。不必从0 开始编码,TCP 在 0 到 之间生成一个随机数作为第一个字节的序号,例如,如果随机数是1057,并且发送的全部字节个数是 6000,那么这些字节序号是 1057~7056。

     在每个连接中传送的字节都由 TCP 编号,序号开始于一个随机产生的数。

3、序号——字节被编号后,TCP 对发送的每一个段分配一个序号。

在每一个方向上的序号定义如下:
1.第一个段的序号是初始序号(initial sequence number,ISN),这是一个随机数。(ISN在三次握手的时候又会出现)
2.其他段的序号是之前段的序号加之前段携带的字节数(实际上的或想象的)。之后,我们将给出一些控制段,它们被认为携带了一个想象字节。

       一个段的序号字段的值定义了该段包含的第一个字节的序号

4、确认号——确认号定义了该方预期接收的下一个字节的序号。另外,确认号是累积的,这意味着接收方记下它已安全而且完整地接收到最后一个字节的序号,然后将它加 1,并将这个结果作为确认号进行通告。

      段中确认字段的值定义了通信一方预期接收的下一个字节的编号。确认号是累积的。

 

 

 


在 TCP 中的分组称为段(segment)。段包含 20 字节到 60 字节的头部,接着是来自应用程序的数据。如果没有选项,那么头部是 20 字节;如果有选项,最多是 60 字节。

1、源端口地址。这是一个 16 位的字段,它定义了在主机中发送该段的应用程序的端口号。这与 UDP 头部的源端口地址的作用一样。
2、目的端口地址。这是一个 16 位的字段,它定义了在主机中接收该段的应用程序的端口号。这与 UDP 头部的目的端口地址的作用一样。
3、 序号。这个 32 位的字段定义了一个数,它分配给段中数据的第一个字节。序号告诉目的端,在这个序列中哪一个字节是该段的第一个字节。在连接建立时,每一方都使用随机数生成器产生一个初始序号(initial sequence number,ISN),通常每一个方向的 ISN 都不同。

4、确认号。这个 32 位的字段定义了段的接收方期望从对方接收的字节号。如果段的接收方成功地接收了对方发来的字节号 x,它就将确认号定义为 x + 1,确认和数据可捎带一起发送
5、头部长度。这个 4 位的字段指明了 TCP 头部中共有多少个 4 字节长的字。头部的长度可以在 20 字节到 60 字节之间。因此,这个字段的值在 5(5 × 4 = 20)到 15(15 × 4 = 60)之间。

           

PSH——push之类,尽快的把我这个包传给应用层

RST——reset重新建立连接

SYN——建立连接的时候用

FIN——断开连接的时候用)

6、窗口大小。这个字段定义对方必须维持的窗口的大小(以字节为单位)

注意,这个字段的长度是 16 位,这意味着窗口的最大长度是 65 535 字节。这个值通常称为接收窗口(rwnd),它由接收方确定。此时,发送方必须服从接收端的支配。
7、 校验和。这个 16 位的字段包含了校验和。TCP 校验和的计算过程与前面描述的 UDP 所采用的计算过程相同。但是,在 UDP 数据报中校验和是可选的。然而,对 TCP 来说,将校验和包含进去是强制的。起相同作用的伪头部被加到段上。对 TCP 伪头部,协议字段的值是6。(现实生产中,不要相信校验和,出错他不管的,内部局域网里,他是不检查的
8、紧急指示符。这个 16 位的字段只有当紧急标志置位时才有效,这个段包含了紧急数据。它定义了一个数,将此数加到序号上就得出此段数据部分中最后一个紧急字节。(可以实现微信的撤销动作,URG表示紧急。当URG的值为1的时候,系统会检查tcp头部第18-19字节的urgent pointer的值。

     

 

 

 

 


TCP连接

      TCP 是一种面向连接的协议。面向连接的传输协议在源端和目的端之间建立一条虚路径。然后,属于一个报文的所有段都沿着这条虚路径发送。整个报文使用单一的虚路径有利于确认处理以及对损坏或丢失帧的重发。

      TCP 的连接是虚连接,不是物理连接。TCP 在一个较高层次上操作,TCP 使用 IP服务向接收方传递独立的段,但它控制连接本身。如果一个段丢失了或损坏了,则重新发送它。与TCP 不同,IP 不知道这个重新发送过程。如果一个段失序到达,则 TCP 保存它直到缺少的段到达。IP 是不知道这个重新排序过程的。

 

1、三次握手(three-way handshaking)

 原因—— TCP 以全双工方式传输数据。当两个机器中的两个 TCP 建立连接后,它们就能够同时向对方发送段。这就表示,在传输数据之前,每一方都必须对通信进行初始化,并得到对方的认可

a)客户发送的第一个段是 SYN 段

这个段仅有 SYN 标志被置位,它用于序号同步。它占用一个序号。当数据传输开始时,客户随机选择一个数字作为初始序号(ISN)。注意,这个段不包含确认号。它也没有定义窗口大小;窗口大小的定义只有当段包含确认号时才有意义。SYN 段是一个控制段并且不携带数据。然而,它消耗一个序号,因为它需要被确认。我们可以说 SYN 段携带了一个假想字节。
       SYN 段不携带数据,但它占用一个序号

b)服务器发送第二个段—— SYN +ACK 段

这个段有两个目的。首先,它是另一方向通信的 SYN 段。服务器使用这个段来初始化序号,这个序号用来给从服务器发向客户的字节编号。服务器也通过给 ACK 置位并展示下一个序号来确认接收到来自客户的 SYN 段,这里的下一个序号是服务器预期从客户接收的序号。因为它包含确认,它也需要定义接收窗口,即 rwnd(客户使用)。因为这个段起到 SYN段的作用,它需要被确认。因此,它占用一个序号。
        SYN + ACK 段不携带数据,但它占用一个序号。

c)客户发送第三个段。这个段仅仅是一个 ACK 段

它使用 ACK 标志和确认序号字段来确认收到了第二个段。注意,如果不携带数据,ACK 段没有占用任何序号。
        ACK 段,如果不携带数据,则它不占用序号。

 

扩展——SYN泛洪攻击(SYN flooding attack)

在 TCP 中,连接建立过程易遭受到称为 SYN 泛洪攻击(SYN flooding attack)的严重安全问题。一个恶意的攻击者将大量的 SYN 段发送到一个服务器,在数据报中通过伪装源 IP 地址假装这些 SYN 段是来自不同的客户端,此时就是 SYN 泛洪攻击。假定客户机发出主动打开,服务器分配必要的资源,如生成转换控制块(TCB)和设置计时器等。然后服务器发送 SYN+ACK 段给这些假客户,但这些段都丢失了。然而,当服务器等待第三段握手过程时,许多资源被占用但没有被使用。如果在短时间内,SYN 段的数量很大,服务器最终会耗尽资源而崩溃。这种 SYN 泛洪攻击属于一种称为拒绝服务攻击(denial of service attack)的安全攻击类型,其中,一个攻击者独占系统如此多的服务请求使得系统崩溃,拒绝对每个请求提供服务

 

2019.01.16补充:

最大消息长度MSS(Maximum Segmengt Size)——IP中不会分片处理的最大数据长度

  • TCP在传输数据时,以MSS的大小将数据进行分割发送。进行重发时也是以MSS为单位。
  • MSS是在三次握手的时候,在两端主机之间被计算得出的。两端的主机在发出建立连接的请求时,会在TCP首部中写入MSS选项,告诉对方自己能接受的最大MSS大小。然后两者会选择较小的那个值进行使用。

 

 


2、数据传输

发送方的 TCP 使用缓冲区存储来自发送方应用程序的数据流。发送方的 TCP 可以选择段的大小。接收方的 TCP 在数据到达时也将数据进行缓存,并当应用程序准备就绪时或当接收端 TCP 认为方便时将这些数据传递给应用程序。

在有些情况下,应用程序并不需要这种灵活性。例如,应用程序与另一方应用程序进行交互式通信。一方的应用程序打算将其击键发给对方应用程序,并希望接收到立即响应。数据的延迟传输和延迟传递对这个应用程序来说是不可接受的。
TCP 可以处理这种情况。在发送端的应用程序可请求推送操作。这就表示发送端的 TCP 不必等待窗口被填满。它创建一个段就立即将其发送。发送端的 TCP 还必须设置推送位(PSH)以告诉接收端的 TCP,这个段所包含的数据必须尽快地传递给接收应用程序,而不要等待更多数据的到来。这意味着将面向字节的 TCP 改为面向块的 TCP,但是 TCP 可以选择使用或不使用这个特性。

TCP 是面向字节流的协议。从应用程序到 TCP 的数据被表示成一串字节流。数据的每一个字节在流中占有一个位置。但是,在某些情况下,应用程序需要发送紧急(urgent)字节,某些字节需要另一端的应用以特殊方式对待。解决方法是发送一个 URG 标志置位的段。TCP 的紧急模式是一种服务,发送端的应用程序通过这种服务将字节流的某些部分标记为需要接收端特别对待的字节流。接收端 TCP 将字节(紧急或非紧急)按序传递到应用程序,但是通知应用程序紧急数据的开始和结束。留给应用程序决定如何处理紧急数据。

 

3、连接终止

     交换数据双方的任一方(客户或服务器)都可关闭连接,尽管通常情况下是由客户端发起。当前大多数对连接终止的实现有两个方法——三次握手和带有半关闭选项的四次握手。

三次握手

当前对连接终止的绝大多数实现是三次握手(three-way handshaking)。
a)在正常情况下,在客户进程接收到一个关闭命令后,客户的 TCP 发送第一个段:FIN 段,即其中的 FIN 标志置位。注意,FIN 段可包含客户机要发送的最后数据块或只是控制段。如果它只是控制段,它仅占有一个序号因为它需要被确认。如果 FIN 段不携带数据,则该段占用一个序号。
b)服务器 TCP 接收到 FIN 段后,通知它的进程,并发送第二个段:FIN + ACK 段,证实它接收到来自客户端的 FIN 段,同时通告另一端连接关闭。这个段还可以包含来自服务器的最后数据块。如果它不携带数据,则这个段仅占用一个序号。如果 FIN + ACK 段没有携带数据,则该段仅占用一个序号。
c)客户端的 TCP 发送最后一段,即 ACK 段,来证实它接收到来自服务器的 FIN 段。这个段包含确认号,它是来自服务器的 FIN 段的序号加 1。这个段不携带数据也不占用序号

四次握手

      在 TCP 中,一端可以停止发送数据后,还可以接续接收数据。这就是所谓的半关闭(half-close)。虽然任一端都可发出半关闭,但通常都是由客户端发起的。当服务器在开始处理之前需要接收到所有数据,这时就会出现半关闭。

     例如,排序是一个很好的例子。客户端发送数据给服务器进行排序,在开始排序之前,服务器需要接收到全部数据。这就是说,客户端发送全部数据之后,它在客户到服务器方向可关闭连接。但为了返回存储数据,服务器到客户方向必须保持打开。服务器在接收到数据后还需要时间进行排序;它的向外方向必须保持打开。

     a)从客户到服务器的数据传输停止。客户端通过发送 FIN 段实现半关闭连接。

     b)服务器通过发送ACK 段确认半关闭。然而,服务器还可以发送数据。

     c)当服务器已经发送完被处理的数据时,它发送一个 FIN 段。

     d)该 FIN 段由客户端的 ACK 来确认。

    连接半关闭后,数据可以从服务器传送给客户端,而确认可以从客户端传送给服务器。客户不能再向服务器发送任何数据。

连接重置

      在一端的 TCP 可能拒绝连接请求,可能终止已存在的连接,也可能结束空闲连接。所有这些都通过 RST(重置)标志完成。

 

 

 

 

状态转换图

图中虚线代表服务器通常经历的转换;黑色实线代表客户通常经历的转换。然而,在某种情况下,服务器沿着实线进行状态转换,客户沿着虚线进行状态转换。蓝色线给出特殊情况。

注意,被标记为 ESTABLISHED 的圆角矩形实际上是两种状态,一个是客户状态,另一个是服务器状态,它们用于流量和差错控制

1、场景示例 —— 一个半关闭场景

      客户进程向它的 TCP 发出主动打开命令来请求连接到特定套接字地址。TCP 发送一个 SYN 段并转移到SYN-SENT状态。在收到SYN + ACK段后,TCP发送了一个ACK段并且进入ESTABLISHED状态。数据被传输,可能是双向的,并且被确认。当客户进程没有数据要发送了,它发出称为主动关闭的命令。TCP 发送 FIN 段并进入 FIN-WAIT-1 状态。当它接收到 ACK 段,它进入 FIN-WAIT-2 状态。当客户接收到 FIN 段时,它发送一个 ACK 段并进入 TIME-WAIT 状态。客户保持这种状态 2MSL秒。当相应计时器超时,客户进入 CLOSED 状态。

      服务器进程发出被动打开命令。服务器 TCP 进入 LISTEN 状态并且保持这种状态直到它接收到一个 SYN 段。TCP 之后发送一个 SYN + ACK 段并且进入 SYN-RCVD 状态,等待客户发送 ACK段。在接收到 ACK 段后,TCP 进入 ESTABLISHED 状态,这就开始了数据传输。TCP 保持这种状态直到它接收到一个来自客户的 FIN 段,这表示没有其他数据要被交换且连接可以被关闭。一旦服务器接收到 FIN 段,那么它就向客户发送带有虚拟 EOF 标记的排队中所有的数据,这意味连接必须被关闭。它发送一个 ACK 段且进入 CLOSE-WAIT 状态,但是推迟确认来自客户的 FIN 段,直到它接收到来自进程的被动关闭命令。在接收到被动关闭命令后,服务器向客户发送 FIN 段并进入 LAST-ACK 状态,等待最终 ACK。当 ACK 段被从客户接收,服务器进入 CLOSE 状态。

————————————————————————————————————————————————————————

版本二:

1、蓝色的线代表服务器

2、棕色的线代表客户端

3、每当客户端连接服务器时,进程会建立新的socket pair,这就是为什么可以同时服务很多个客户端的原因。

4、服务器尽肯能的不要去主动关闭socket

5、当客户端主动调用close函数,他就进入active close状态,进入fin awit状态,之后客户端发送ack,进入fin wait2状态。之后发送ack,进入time wait状态。

6、虽然客户端和服务器都可以进入time wait状态,但是最好服务器不要进入这样的状态

因为(最好结合上图一起查看)当进入time wait状态时,此时整个的socket pair处于不可用的状态,之后等待timeout这么长的时间之后,客户端进入closed状态。(注意:从time wait,经历过timeout这段时间到达closed状态的这段时间,进入time wait状态的socket pair是不可用的。今天time wait状态的socket pair,一定要经历timeout这么长的等待时间,才可以再次复用

 

 

TCP中的窗口

      TCP 在每个方向的数据传输上使用两个窗口(发送窗口和接收窗口),这意味着双向通信有四个窗口。

1、发送窗口

      发送窗口大小由接收方(流量控制)和底层网络的拥塞程度(拥塞控制)指定。

TCP 中的发送窗口与选择性重复协议中的发送窗口相似,但是有一些不同:

a)在 SR 中窗口的大小是分组的数量,但是 TCP 中的窗口大小是字节的数量。尽管 TCP 中实际传输是一段接一段发生的,但是控制窗口的变量是以字节为单位的。

b)在某些实现中,TCP 可以存储来自进程的数据并且在之后发送它们,但是我们假设发送方 TCP 一旦从进程中接收到数据就能够发送数据段。

c)选择性重复协议可能为每个被发送的分组使用多个计时器,而 TCP 只使用一个计时器

2、接收窗口

TCP 中的接收窗口与 SR 中的接收窗口有两点不同。

a) TCP 允许接收进程以自己的速率拉数据。这意味着接收方部分被分配缓冲区可以被已接收且确认的字节占据,但是它们正在等待被接收进程拉过去。接收窗口大小决定了接收窗口在被淹没(流量控制)之前可以从发送方接收的字节数量。换言之,接收窗口通常称为 rwnd,可以由下式决定:
             rwnd = 缓冲区大小  − 等待被拉字节数量

b)在 SR 中的确认是选择性的,它定义了已经被接收的分组。TCP 中主要确认机制是累积确认,它声明了下一个预期接收字节。然而,TCP 的新版本使用了累积确认和选择性确认。

 

 

 

流量控制

流量控制平衡了生产者创建数据的速率与消费者使用数据的速率。TCP 将流量控制与差错控制分开。

图 3-56 给出了从发送方进程到发送方 TCP、从发送方 TCP 到接收方 TCP 以及从接收方 TCP上升到接收方进程的数据(路径 1、2 和 3)传输过程。然而,流量控制反馈却是从接收方 TCP 传输到发送方 TCP 并且从发送方 TCP 上升到发送方进程(路径 4 和 5)。绝大多数 TCP 实现不提供从接收方进程到接收方 TCP 的流量控制反馈;无论何时,当接收方进程准备好了,具体实现就会让接收方进程从接收方 TCP 中拉数据。

接收方 TCP 控制发送方 TCP;发送方 TCP 控制发送方进程。

 

1、打开以及关闭窗口

为了实现流量控制,TCP 迫使发送方和接收方调整它们的窗口大小,尽管当连接建立时两方的缓冲区大小是固定的

a)当更多的数据从发送方到来时,接收方窗口关闭(向右移动左沿);

b)当更多的数据被进程拉过来时,它打开窗口(向右移动右沿)。

发送窗口的打开、关闭和收缩由接收方控制

a)当一个新的确认允许发送窗口关闭时,发送窗口关闭(向右移动左沿)。

b)当接收方通知的接收窗口大小(rwnd)允许发送方窗口打开时(新 ackNo +新 rwnd > 上一个 ackNo + 上一个 rwnd),发送窗口打开(向右移动右沿)。这种情况没有发生的事件中,发送窗口缩小。

 

2、例子

客户和服务器之间交换了 8 个段。

三次握手部分:
a)从客户到服务器的第 1 段(SYN 段)请求连接。这个段声明起始 seqNo = 100。当这个段到达服务器时,它分配了大小为 800 字节的缓冲区(假设)并设置窗口覆盖了全部缓冲区(rwnd =800)。注意,下一个要到达的字节是 101。
b)第 2 段是从服务器到客户的。这是 ACK + SYN 段。段使用 ackNo = 101,这表示它期待接收的字节从 101 开始。它也声明了客户可以设置大小为 800 字节的缓冲区。
c)第 3 段是从客户到服务器的 ACK 段。注意,客户可以定义大小为 2000 的 rwnd,但是,在图 3-57 中我们不使用这个值,因为通信是单向的。

数据传输部分:
a)在客户设置了服务器指定的窗口大小(800)之后,进程推送 200 字节数据。TCP 客户给这些字节编号为从 101 到 300。之后,它创建了一个段并发送到服务器。段开始字节数是 101 并且携带了 200 字节。之后客户窗口调整,表示 200 字节数据被发送但是等待确认。当这个段被服务器接收,这些字节被存储,并且接收窗口关闭来表示下一个预期字节是 301;存储字节占据了缓冲区的 200 字节。
b)第 5 段是从服务器到客户的反馈。服务器确认了多达 300 个字节,含第 300 个字节(预期接收 301 字节)。这个段也携带了减少后的接收窗口大小(600)。在接收这个段之后,客户从它的窗口中清除确认字节并关闭它的窗口,这表示下一个待发送字节是 301。然而,窗口大小减少到 600字节。尽管分配缓冲区可以存储 800 字节,但是窗口不能打开(向右移动右沿),因为接收方不允许。
c)在进程又推送了 300 个字节后,第 6 段被客户发送。段定义了 seqNo 为 301,并包含了 300字节。当这个段到达服务器,服务器存储它们,但是它必须减少自己的窗口大小。在进程拉 100字节数据后,窗口左边关闭了 300 字节,但是右侧打开了 100 字节。结果是窗口大小只减少了 200字节。现在接收窗口大小是 400 字节。
d)在第 7 段,服务器确认接收数据,并声明它的窗口大小是 400。当这个段到达客户,客户别无选择,只能再次减少它的窗口,并令窗口大小为服务器通告的 rwnd = 400。发送窗口从左侧关闭 300 字节,并从右侧打开 100 字节。
e)在进程拉另外 200 字节后,第 8 段也是从来自服务器的。它的窗口大小增加。现在,新的rwnd 的值是 600。段告知客户,服务器仍然期待 601 字节,但是服务器窗口大小增加到 600。我们需要提及的是,这个段的发送依赖于具体实现所规定的策略。一些实现可能不允许在这个时候通告rwnd;服务器需要在这样做之前接收一些数据。在这个段到达客户之后,客户将窗口打开 200 字节而不关闭。结果是窗口增大到 600 字节。

 

3、窗口收缩

接收窗口不能收缩,但是发送窗口可以收缩——如果接收方为 rwnd 定义了导致窗口收缩的数值,那么发送窗口可以收缩。然而,一些实现不允许收缩发送窗口。这个限制不允许发送窗口的右沿向左移动。换言之,接收方需要保持上一个和新的确认之间以及上一个和新 rwnd 值之间的如下关系,以防止发送窗口收缩。

                新 ackNo +新 rwnd≥上一个 ackNo +上一个 rwnd

不等式是对接收端的命令,它使接收端检查自己的通告。

 

4、窗口关闭
我们说过,不鼓励将右沿向左移动来收缩发送窗口。然而,有一个例外:接收方可以通过发送rwnd 为 0 来临时关闭窗口。这只会在某些原因下发生,即接收方在一段时间内不想接收来自发送方的任何数据。在这种情况下,发送方并不真的收缩窗口大小,但是它停止发送数据直到新的通告到达。我们将在后面看到,即使当窗口因为来自接收方的命令而关闭了,发送方也总可以发送一个1 字节数据的数据段。这称为探测,用来防止死锁。

 

 

 

差错控制

TCP 使用差错控制提供可靠性。差错控制包括用于检测并重发损坏段的机制、用于重发丢失的段的机制、用于存储失序的段直到丢失段到达的机制,以及检测并丢弃重复段的机制。TCP 中的差错检测和纠正通过三种简单工具来完成:校验和、确认和超时。

1、校验和

每个段都包括校验和字段,用来检查损坏的段。如果段被损坏,它将被目的端 TCP 丢弃,并被认为是丢失了。TCP 在每段中强制使用一个 16 位的校验和。

2、确认

TCP 使用确认方法来证实收到了数据段。不携带数据但占用序号的一些控制段也要确认,但ACK 段是不确认的。
        ACK 段不占用序号,它不需要确认。

 

确认类型
在过去,TCP 只使用一种类型确认:累积确认。现在,一些 TCP 实现也使用选择性确认。

累积确认(ACK) 最初的 TCP 被设计成累积确认接收段。接收方通告下一个预期接收的字节,忽略所有失序段。这有时称为积极累积确认(positive cumulative acknowledgment)或 ACK。积极这个词表示不为丢弃、丢失或被破坏的段提供反馈。TCP 头部的 32 位 ACK 字段用来累积确认,且只有当 ACK 标志位置为 1 时才有效

选择性确认(SACK) 越来越多的实现加入了另外一种称为选择性确认(selective acknowledgment)或 SACK 的确认类型。SACK 并不替代 ACK,但它向发送方报告额外的信息。SACK 报告失序字节块,也报告重复字节块即接收了一次以上的字节块。然而,因为 TCP 头部没有为加入这种类型的信息做准备,SACK 以一种 TCP 头部末端选项的形式实现。

 

产生确认

接收方什么时候产生确认?
1.当终端 A 向终端 B 发送一个数据段时,它必须包含(捎带)一个确认,这个确认给出下一个期待接收的序号。这个规则降低了所需段的数量,因此减少了通信量。
2.当接收方没有数据要发送并接收到一个有序段(带有预期序号),并且之前的段已经被确认,那么接收方延迟发送 ACK 段直到另一个段到达,或者过一段时间之后(通常 500ms)。换言之,如果只有一个未完成的有序段,那么接收方需要延迟发送 ACK 段。这个规则减少了 ACK 段。
3.当一个带有接收方预期序号的段到达,且之前一个有序段未被确认,接收方立即发送一个到这了ACK 段。换言之,任何时候不能多于两个有序的未确认段存在。这防止了不必要的重传,它可能引起网络拥塞。
4.当一个失序段到达,且它的序号大于预期,那么接收方立即发送一个 ACK 段,声明下一个预期段的序号。这导致了丢失段的快速重传(fast retransmission)。
5.当一个丢失段到达,接收方发送一个 ACK 段,声明下一个预期序号。这通知接收方被报告丢失的段已经到达。
6.如果重复段到达,接收方丢弃段,但是立即发送一个确认指出下一个预期的有序段。这个方法解决了当 ACK 段丢失时的一些问题。

 

重传

差错控制机制的核心是段的重传。当一个段被发送,它就被储存在一个队列中直到被确认。当重传计时器超时或当发送方接收到对队列中的第一个段的三次重复 ACK 时,就重传这个段。

RTO 之后重传
发送方 TCP 为每个连接维护一个重传超时(retransmission time-out,RTO)。当计时器到时,即超时,TCP 重发队列前面的段(具有最小序号的段)并重启计时器。注意, RTO 的数值在 TCP 中是动态的,并根据段的往返时间(round-trip time,RTT)进行更新。RTT 是一个段到达目的端并接收到一个确认所需要的时间
 

三次重复 ACK 段之后重传
快速重传(fast retransmission):如果三个对同一个段的重复确认(即一个原始 ACK 加上三个完全相同的副本)到达,那么下一个段就被重传而不必等待超时。

 

2019.1.16补充

发送端主机如果连续三次收到同一个确认应答,就会将其对应的数据进行重发。

 


TCP拥塞控制

拥塞窗口
当我们讨论 TCP 中的流量控制,我们曾提到过接收方使用 rwnd 的数值来控制发送窗口,它在每个沿相反方向传递的段中被通告。使用这个策略保证了接收窗口不会被接收字节溢出(没有终端拥塞)。然而,这不意味着中间缓冲区、路由器中的缓冲区不会变得拥塞。路由器可能从不止一个发送端接收数据。无论路由器的缓冲多大,它都可能被数据淹没,这导致特定 TCP 发送方丢弃某

些段。换言之,在另一端不存在拥塞,但是可能在中间存在拥塞。TCP 需要担心中间的拥塞,因为很多丢失段可能导致差错控制。更多的段丢失意味着再次重发相同的段,导致拥塞更严重,并且最终导致通信崩溃。

TCP 是使用 IP 服务的端到端协议。路由器中的拥塞是在 IP 域内,并且应该由 IP 解决。然而,IP 是一个没有拥塞控制的简单协议。TCP 自身需要为这个问题负责。

TCP 使用称为拥塞窗口(congestion window,cwnd)的变量来控制段的发送数量,这个变量的值由网络中的拥塞情况所控制。cwnd 变量和 rwnd 变量一起定义了 TCP 中的发送窗口大小。第一个变量与中间的拥塞相关(网络);第二个变量与终端的拥塞相关。实际窗口的大小是这两者中的最小值。   

                   实际窗口大小 = minimum (rwnd, cwnd)

拥塞检测
TCP 发送方使用两个事件作为网络中拥塞的标志:超时和接收到三次重复 ACK。
第一个是超时(time-out)。如果一个 TCP 发送方在超时之前没有接收到对于某个段或某些段的 ACK,那么它就假设相应段或相应那些段丢失了,并且丢失是拥塞引起的。
另一个事件是接收到三次重复 ACK(四个带有相同确认号的 ACK)。回忆当 TCP 接收方发送一个重复 ACK,这是段已经被延迟的信号,但是发送三次重复 ACK 是丢失段的标志,这可能是由于网络拥塞造成的。然而,在三次重复 ACK 的情况下拥塞的严重程度低于超时情况。当接收方发送三次重复 ACK 时,这意味着一个段丢失,但是三个段已经被接收到。网络或者轻微拥塞或者从已经从拥塞中恢复。
TCP 拥塞中非常有趣的一点是,TCP 发送方只使用一种反馈从另一端来检测拥塞:即 ACK。没有周期性地、及时地接收到 ACK,这导致超时,是严重拥塞的标志;接到三次重复 ACK 是网络中轻微拥塞的标志

 

拥塞策略
TCP 处理拥塞的一般策略基于三个算法:慢启动、拥塞避免和快速恢复

慢启动:指数增加
慢启动(slow-start)算法是基于拥塞窗口大小(cwnd)的思想,它以最大段长度(MSS)开始,但是每当一个确认到达时它只增加一个 MSS。

看图 3-66。我们假设 rwnd 比 cwnd 大得多,因此发送窗口大小永远等于 cwnd。我们也假设每个段是同长度的,并携带 MSS 字节。为了简单起见,我们也忽略延迟 ACK 策略并假设每个段单独被确认。

发送方以 cwnd = 1 开始。这意味着发送方仅能发送一个段。当第一个 ACK 到达后,被确认的段被从窗口中清除,这意味着现在窗口中有一个空段槽。拥塞窗口的大小也增加 1,因为收到确认标志着网络中没有拥塞。窗口的大小现在是 2。在发送两个段并接收到两个独立的确认之后,现在拥塞窗口的大小是 4,依此类推。换言之,在这个算法中拥塞窗口的大小是到达 ACK 数量的函数,可由下式决定。

                       如果一个 ACK 到达,cwnd = cwnd + 1

如果我们按照往返时间(RTT)观察 cwnd 的大小,那么我们发现其增长速率是指数的,这是一个非常激进的方法:

慢启动不能一直继续下去。肯定存在一个停止该阶段的阈值。发送方保存一个称为 ssthresh(slow-start threshold,慢启动阈值)的变量。当窗口中的字节达到这个阈值时,慢启动停止且下一个阶段开始。

在慢启动算法中,拥塞窗口大小按指数规律增长直到到达阈值。然而,我们已经提到慢启动策略在延迟确认情况下更慢。请记住,对于每个 ACK,cwnd 值增加 1。因此,如果两个段被累积确认,cwnd 大小只增加 1 不是 2。增长仍是指数的,但是它不是 2的幂。对于确认了两个段的 ACK,它是 1.5 的幂。

拥塞避免:加性增加
如果我们继续慢启动算法,那么拥塞窗口大小按指数规律增大。为了在拥塞发生之前避免拥塞,必须降低指数增长的速度。TCP 定义了另一个算法,称为拥塞避免(congestion avoidance),这个算法是线性增加 cwnd 而不是指数增加。当拥塞窗口的大小到达慢启动的阈值时,这种情况下 cwnd= i,慢启动阶段停止且加性增加阶段开始。

在这个算法中,每次整个“窗口”的所有段都被确认(一次传输),拥塞窗口才增加 1。窗口是 RTT 期间传输的段的数量。图 3-67 说明了这个概念。发送方以 cwnd = 4 开始。这意味着发送方只能发送 4 个段。在 4 个 ACK 到达之后,被确认的段被从窗口中清除,这意味着现在窗口中有一个空闲段。拥塞窗口也增加 1。窗口大小现在为 5。在发送 5 个段并接收到 5 个确认之后,拥塞窗口大小变为 6。其余以此类推。换言之,这个算法中拥塞窗口的大小也是到达的 ACK 数量的方程,它由下式决定:

                         如果一个 ACK 到达,cwnd = cwnd + (1/cwnd)。

换言之,窗口大小每次只增加 MSS 的 1/cwnd(以字节为单位)。换言之,窗口中所有段都需要被确认,才能使窗口增加 1MSS 字节。

如果我们按照往返时间(RTT)观察 cwnd 的大小,那么我们会发现其增长速率以每次往返时间为单位是线性的,这比慢启动方法保守多了。

开始 →  cwnd = i
第一个 RTT 之后  →  cwnd = i + 1
第二个 RTT 之后  →  cwnd = i + 2
第三个 RTT 之后  →  cwnd = i + 3

在拥塞避免算法中,在检测到拥塞之前,拥塞窗口大小是加性增加的

快速恢复

快速恢复(fast-recovery)算法在 TCP 中是可选的。旧版本的 TCP 不使用它,但是新版本使用。快速恢复开始于三次重复 ACK 到达,这被解释为网络的轻微阻塞。像拥塞避免一样,这个算法也是加性增加的,但是当一个重复 ACK 到达时(在三次重复 ACK 触发使用这个算法之后),它增加拥塞窗口的大小。我们可以说:
                   如果一个重复 ACK 到达,cwnd = cwnd + (1/cwnd)。

 

 2MSL(2 Maximum Segment Lifetime,2 倍段最大生存时间)

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值