运输层——TCP协议

1. 报文格式

在这里插入图片描述
序号:占4字节。序号范围是 0 到 2 的32次方-1 ,序号增加到 2的32次方-1 后,下一个序列号就回到了1。也就是说,序号使用mod 2的32次方 运算。TCP是面向字节流的,TCP连接中传送的字节流中的每一个字节都按顺序编号。首部中的序号就是指本报文段所发送数据的第一个字节的序号

确认号:占4个字节,是期望收到对方下一个报文段的一个数据字节的序号

确认ACK:当ACK=1时,确认号有效,当ACK=0时,确认号无效。当建立连接后所有传送的报文段都必须把 ACK 置1。

同步SYN:当SYN=1,ACK=0 时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使 SYN=1 和 ACK= 1 。因此, SYN 置为 1 就表示这是一个连接请求或连接接受报文。

终止FIN:当FIN=1时。表明此报文的发送方的数据已经发送完毕,并要求释放运输连接。

2. 三次握手

在这里插入图片描述

  1. 客户端发起连接请求报文段,SYN = 1,自己的初始序号 seq = x
  2. 当服务器接收到请求后,发送一个连接接受报文段,SYN=1,ACK=1,自己的初始序号 seq = y,确认号 ack = x + 1
  3. 当客户端收到接受报文后,再发送一条确认,此时ACK=1,确认号 ack = y + 1,序号 x + 1

丢包情况:

第一个包,即 A 发给 B 的 SYN 中途丢失,没有到达 B :

A 会周期性超时重传,直到收到 B 的确认。

第二个包,即 B 发送给 A 的 SYN + ACK 中途丢失,没有到达 A :

B 会周期性超时重传,直到收到 A 的确认。

第三个包,即 A 发送给 B 的 ACK 中途丢失,没有到达 B :

A 发完 ACK ,单方面认为 TCP 为 Established 状态,而 B 显然认为 TCP 为 Active 状态:

a.假定此时双方都没有数据发送,B 会周期性超时重传,直到收到 A 的确认,收到之后连接建立。

b.假定此时 A 有数据发送,B 收到 A 的 Data + ACK ,自然会切换为 Established 状态。

c.假定此时 B 有数据发送,发送不了,B 会周期性超时重传,直到收到 A 的确认,收到之后连接建立。

为什么需要三次握手,二次和四次不行?

TCP作为一种可靠传输控制协议,既要保证数据可靠传输,又要提高传输的效率,而三次恰恰可以满足这两方面的需求。

四次握手过程:

  1. A 发送同步信号 SYN + A 的初始序号x
  2. B 发送一个确认报文段 (ACK= 1, ack = x + 1)
  3. B 再发送一个同步报文段 (SYN = 1, seq = y)
  4. A 发送一个确认报文段(ACK= 1, ack = y + 1)

显然 2、3 步骤可以合并,提高连接速度与效率。

两次握手过程:

  1. A 发送同步信号 SYN + A 的初始序号x
  2. B 发送同步信号 SYN + B 的初始序号y + 确认 ACK = 1 + 确认序号 x + 1

这里的问题是,此时 A 与 B 就 A 的初始序号达成了一致,但是 B 无法知道 A 是否已经接收到自己的同步信号,如果这个同步信号丢失了,A 和 B 就B的初始序号将无法达成一致。

一句话概括,TCP 连接握手,握的是啥?

通信双方数据原点的序列号。

3. 四次挥手

在这里插入图片描述

  1. A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。 A 把连接释放报文段首部的终止控制位 FIN 置 1, 其序号 seq = u, 它等于前面已传送过的数据的最后一个字节的序号加 1 。这时 A 进入 FIN-WAIT-1 (终止等待 1) 状态,等待 B 的确认。
  2. B 收到连接释放报文段后即发出确认,确认号是 ack = u + 1, 而这个报文段自己的序号是 V, 等于 B 前面已传送过的数据的最后一个字节的序号加 1 。然后 B 就进入 CLOSEWAIT (关闭等待)状态。TCP 服务器进程这时应通知高层应用进程,因而从 A 到 B 这个方向的连接就释放了,这时的 TCP 连接处于半关闭 (half-close)状态,即 A 已经没有数据要发送了,但 B 若发送数据, A 仍要接收。也就是说,从 B 到 A 这个方向的连接并未关闭,这个状态可能会持续一段时间。 A 收到来自 B 的确认后,就进入 FIN-WAIT-2 (终止等待 2) 状态,等待 B 发出的连接释放报文段。
  3. 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接。这时 B 发出的连接释放报文段必须使 FIN= 1 。现假定 B 的序号为 w (在半关闭状态 B 可能又发送了一些数据)。 B 还必须重复上次已发送过的确认号 ack = u + 1 。这时 B 就进入 LAST-ACK (最后确
    认)状态,等待 A 的确认。
  4. A 在收到 B 的连接释放报文段后,必须对此发出确认。在确认报文段中把 ACK 置 1,确认号 ack = w + 1, 而自己的序号是 seq=u+1。但此时TCP连接并没有释放掉,A还需要经过时间等待计时器设置的时间2MSL后,TCP连接才完全释放。第一为了保证 A 发送的最后一个 ACK 报文段能够到达 B 。第二,A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL, 就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

为什么是4次挥手?

最本质的原因在于TCP是全双工,数据是双向流动的,没有所谓的主从关系。客户机请求断开,只是客户机不会再向服务器发送数据了。这个时候服务器还可以继续处理客户机之前发送上来的数据,然后返回给客户机,四次断开就给服务器留下了一个处理尾部数据的时间,当服务器数据全部处理完了,并且也返回给客户机了,这个时候服务器就同样可以发送 FIN 信号了。这个完全符合我们生活之中实际的例子。

4. TCP 怎么保证可靠性

4.1 TCP 是面向连接的字节流协议

连接意味着需要三次握手和四次挥手,确保连接和断开的过程可靠。

4.2 超时重传、应答及数据校验机制

TCP 每发出报文,都会在发送时设置一个重传定时器,如果当定时器溢出时还没有收到确认,它就重传该数据;并且当收到的数据报校验出错,主端不会发送响应报文,直到对端重传。

4.3 慢启动和拥塞控制

为什么需要慢启动?

当主机开始发送数据时,由于并不清楚网络的负荷情况,所以如果立即把大量数据字节注入到网络,那么就有可能引起网络发生拥塞。经验证明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。

为什么需要拥塞避免?

慢启动完成之后,拥塞窗口会持续增大,但是当拥塞窗口增加过快,可能导致过多的数据注入到网络中,引起整个网络的拥塞,从而需要拥塞避免。

什么时候确定拥塞发生?

发送方发送一些报文段时,如果发送方没有在时间间隔内收到接收方的确认报文段(响应超时),则就可以认为网络出现了拥塞,就可以进入拥塞避免算法。

慢启动和拥塞避免算法原理?

拥塞避免算法和慢启动算法需要对每个连接维持两个变量:一个拥塞窗口cwnd(用来表示发送方在得到接收方确认前,最大允许传输的未经确认的数据)和一个慢启动门限ssthresh(超过此门限则启动拥塞避免算法),通过两个变量的值确定使用慢启动算法还是拥塞避免算法。

慢启动算法:就是在主机刚开始发送数据报的时候先探测一下网络的状况,如果网络状况良好,发送方每发送一次文段都能正确的接受确认报文段。那么就从小到大的增加拥塞窗口的大小,即增加发送窗口的大小。慢启动算法是指数增加,初始设置cwnd为1个报文段,此后每收到一个确认就加1,那样,这会使窗口按指数方式增长:发送1个报文段,然后是2个,接着是4个等等。 慢启动简单的例子:开始发送方先设置cwnd(拥塞窗口)=1,发送第一个报文段M1,接收方接收到M1后,发送方接收到接收方的确认后,把cwnd增加到2,接着发送方发送M2、M3,发送方接收到接收方发送的确认后cwnd增加到4,慢启动算法每经过一个传输轮次(认为发送方都成功接收接收方的确认),拥塞窗口cwnd就加倍。

拥塞避免算法:为了防止cwnd增加过快而导致网络拥塞,所以在适当的时候需要启动拥塞避免算法。拥塞避免算法使得cwnd缓慢的增加而不是加倍的增长,每经历过一次往返时间就使cwnd增加1,而不是加倍。这样使cwnd缓慢的增长,比慢启动要慢的多。

当拥塞发生时候,两种算法如何配合工作? 无论是慢启动算法还是拥塞避免算法,只要判断网络出现拥塞,就要把慢启动开始门限(ssthresh)设置为发送窗口的一半(>=2),cwnd(拥塞窗口)设置为1,然后再使用慢启动算法,这样做的目的能迅速的减少主机向网络中传输数据,使发生拥塞的路由器能够把队列中堆积的分组处理完毕。慢启动算法拥塞窗口按指数增加,拥塞窗口是按照线性的规律增长,比慢启动算法拥塞窗口增长慢的多。

二者配合工作简单实例:

  1. TCP 连接进行初始化的时候,cwnd=1,ssthresh=16。
  2. 连接刚开始使用慢启动算法发送数据,在慢启动算法开始时,cwnd的初始值是1,每次发送方收到一个ACK拥塞窗口就增加1,当ssthresh = cwnd时,就启动拥塞控制算法,拥塞窗口按照规律增长。
  3. 当cwnd=24时,网络出现超时,发送方收不到确认ACK,此时设置ssthresh=12,(二分之一cwnd),并设置cwnd=1,然后重新开始慢启动算法,当cwnd = ssthresh = 12,慢启动算法变为拥塞控制算法,cwnd按照线性的速度进行增长。

在这里插入图片描述

4.4 快重传与快恢复

快速重传:针对接收方收到失序报文的算法。快重传算法要求首先接收方收到一个失序的报文段后就立刻发出重复确认,而不要等待自己发送数据时才进行捎带确认。例如当接收方成功的接受了发送方发送来的M1、M2并且分别给发送了ACK,现在接收方没有收到M3,而接收到了M4,显然接收方不能确认M4,因为M4是失序的报文段。如果根据可靠性传输原理接收方什么都不做(如果接收方需要发送数据也可以将M2的ACK重新捎带发过去),但是按照快速重传算法,在收到M4、M5等报文段的时候,不断重复的向发送方发送M2的ACK。该重复的ACK的目的在于让对方知道收到一个失序的报文段,并告诉对方自己希望收到的序号告诉对方我要M3啊,你快点发给我。ACK序列其实就是我这边要接收的下一个报文。如果接收方一连收到三个重复的ACK,那么发送方不必等待重传计时器到期,直接重传相应的报文。如果1,2,4,5号的收到了,3号丢失,那么发送端仅重发3还是全部重发3,4,5。快速重传,连续发送三次2号的ACK告诉你发送3号过来。然后再响应5号,这样发送方就知道。

快速恢复算法:当发送发连续接收到三个确认时,就执行拥塞避免算法,把慢启动开始门限(ssthresh)减半,但是接下来并不执行慢启动算法。而是把cwnd设置为ssthresh的一半, 然后执行拥塞避免算法,使拥塞窗口缓慢增大,这就是快速恢复算法。

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章