传输层——TCP(详解三路握手与四次挥手)

Posted Shemesz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了传输层——TCP(详解三路握手与四次挥手)相关的知识,希望对你有一定的参考价值。

TCP协议

一、TCP协议

1. TCP协议概述

  TCP协议与电话语音通信相似,是面向连接的、可靠传输、有流量控制、拥塞控制、面向字节流传输、提高网络利用率等诸多优点的协议。其最终功能与UDP一样,提供进程间端对端的通信,但和UDP区别还是很大的


2. TCP协议要点

  • 1)当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段最大传输段大小(MSS) 通常受该计算机连接的网络的数九链路层的 最大传送单元(MTU) 的限制;
  • 2)TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接受。然后接收端实体对已成功接收到的字节回复一个相应的确认(ACK);
    重传:如果发送端实体在合理的 往返时延(RTT) 内未收到确认,那么对应的数据将会被重传;

3. TCP报文结构

  • 源端口和目的端口号:知道谁发给谁的;
  • 序号:编号是为了解决乱序问题;
  • 确认应答:发出去的包应该收到的确认,没有收到就重传,直到送达;
  • 控制位SYN是发起一个连接、ACK是回复、RST是重新连接、FIN是结束连接;
  • 窗口大小:TCP要做流量控制,通信双方个申明一个窗口,标识自己当前能够处理的能力,通俗来说就是,别发送太快,撑死我,也别发送太慢,饿死我;

4. 面向连接——三路握手

  TCP提供面向有连接的通信传输,面向有连接是指在数据通信开始之前先做好两端的准备工作;所谓的三路握手是指建立一个TCP连接时需要客户端和服务器端总共发送三个包以确认连接到建立。在socket编程当中,这一过程由客户端执行connect来触发。

     模式:请求 -> 应答 -> 回应应答

  • 第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端的确认;
  • 第二次握手:服务器端收到数据包后有标志位SYN=1知道客户端请求建立连接;服务器端将标志位的ACK和SYN都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端已确认请求连接,服务器端进入SYN_RCVD状态;
  • 第三次握手:客户端收到确认以后,检查ack是否等于J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端会检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端与服务器端进入到ESTABLISHED(已建立)状态,完成三次握手,随后客户端与服务器端就可以开始传输数据了。

5. 断开连接——四次挥手

  四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务器端总共发送4个包以确认连接的断开。在socket编程当中,这一过程客户端或服务器端任一方执行close来触发。由于TCP连接是全双工的,因此每个方向必须要有单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一个方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上任然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方执行主动关闭,而另一方则执行被动关闭。

  • 第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说:“我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据;
  • 第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没有准备好 ,请继续等我的消息。这个时候客户端就进入到FIN_WAIT_2状态了,继续等待服务器端的FIN报文;
  • 第三次挥手:当服务器端确定数据已经发送完成,则向客户端发送FIN=N报文,告诉客户端我这边的数据发送完成了,准备好关闭连接了。服务器端进入LAST_ACK状态;
  • 第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送一个ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传,服务器端收到ACK后就知道可以断开链接了。客户端等待了2MSL(最大报文存活时间) 后依然没有收到回复,则证明服务器端已正常关闭了,那好,我的客户端也可以关闭连接了,最终完成了四次挥手。

四次挥手的原因
客户端发送了FIN连接释放报文之后,服务器收到了这个报文,就进入了CLOSE_WAIT状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器端会发送FIN连接释放报文。

TIME_WAIT
客户端接受到服务器端的FIN=N报文后进入time_wait状态,此时并不是直接进入CLOSE状态了,还需要等待一个时间计时器设置的时间2MSL,这么做有两个理由:

  • 确保最后一个报文能够到达。如果B没有收到A 发送来的确认报文,那么就会重新发送连接释放请求报文,客户端A等待2MSL就是为了处理这种情况的发生;
  • 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

二、TCP为什么是可靠传输

  要成为一个可靠的协议,必须要许多机制保证传输的可靠性,通过数据编号和积累确认、以字节为单位的滑动窗口、超时重传、快速重传这四个方面来达到可靠性。

1. 数据编号与积累确认

数据编号:序列号是按照顺序给发送数据的每一个字节(8位字节)都标上号码的编号。接收端查询接收数据 TCP 首部中的序列号和数据的长度,将自己下一步应该接收的序列号作为确认应答返送回去。通过序列号和确认应答号,TCP 能够识别是否已经接收数据,又能够判断是否需要接收,从而实现可靠传输。
积累确认:服务器端不是接收到一个字节就发一个确认,那样效率太低,而是当接收到4,5个时,在发送一个确认,那么在之前的确认之前的数据就算发送成功了的。


2. 超时重传

TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。

  • 重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过这个时间仍未收到确认应答,发送端将进行数据重发。最理想的是,找到一个最小时间,它能保证“确认应答一定能在这个时间内返回”;
  • TCP 要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵情况发生何种变化,都必须保持这一特性。为此,它在每次发包时都会计算往返时间及其偏差。将这个往返时间(RTT)和偏差时间相加,重发超时的时间就是比这个总和要稍大一点的值;
  • 在 BSD 的 Unix 以及 Windows 系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍。不过,最初其重发超时的默认值一般设置为6秒左右;
  • 数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长;
  • 此外,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

3. 滑动窗口

  窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小

  • 发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。

  • 接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 31, 34, 35,其中 31 按序到达,而 34, 35 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。

4. 流量控制

在传输层中,有接受缓存和发送缓存这两个东西的存在,所以每次发送数据过去另一端时,都会把这些数据给带过去,让对方知道自己的这两个缓存的大小,然后来合理的设置自己的发送窗口的大小,流量控制是为了控制发送方发送速率,保证接收方来得及接收。

  • 如果对方的缓存快满了,对方在传送数据过来的时候,就会告诉自己,少发一点数据过来,自己就设置滑动窗口小一点,让对方有缓冲的机会,而不会导致缓存溢出,不让自己的报文被丢弃。
  • 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。

5. 拥塞控制

  如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。

  • 流量控制是为了让接收方能来得及接收;
  • 拥塞控制是为了降低整个网络的拥塞程度

拥塞控制站的角度更大,此时既考虑了对方接收不过来,缓存太多溢出导致,又考虑在线路中,线路上的传输速率就那么大,但是有很多人同时用,发送的数据太多,就会使线路发现拥塞,也就是路由器可能转发不过来,导致大量数据丢失,这两个问题。所以拥塞控制这个解决方案,大概意思就是当检测到有网络拥塞时,就会让自己的滑动窗口变小,但具体是怎么变化的,就是根据算法来算了.

TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复
发送方需要维护一个叫做拥塞窗口(cwnd) 的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。


1)慢开始和拥塞避免

  • 发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …
  • 注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1
  • 如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
    ————————————————————————————————

2)快重传和快恢复

  • 接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
    发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
  • 在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。

慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。

以上是关于传输层——TCP(详解三路握手与四次挥手)的主要内容,如果未能解决你的问题,请参考以下文章

TCP三次握手与四次挥手详解

TCP的三次握手与四次挥手(详解+动图)

TCP三次握手与四次挥手

网络编程:TCP/IP协议的三次握手与四次挥手

TCP三次握手与四次挥手

TCP三次握手与四次挥手