Skip to content

Files

Latest commit

3b4781d · May 16, 2019

History

History
215 lines (155 loc) · 14.3 KB

TCP.md

File metadata and controls

215 lines (155 loc) · 14.3 KB

1、相关概念

相关概念这部分,描述了tcp协议中涉及的几处概念,相当于名词解释。
建议阅读时先扫一遍这部分。后续阅读中,如果涉及相关概念,在回来差字典。便于理解。(可以开两个网页来看。)

1.1、报文结构

报文结构

tcp传输控制协议 ,以上是tcp的报文结构,其各部分表示的含义如下:

  • 16位的源端口与目标端口分别表示了,数据从哪个进程来,到哪个进程去。
  • 32位序号(Sequence Number简写seq),用以解决网络包乱序问题。
  • 32位确认序号(Acknowledgement Number简写ack),用以解决丢包问题。
  • 4位首部长度:表示tcp报头有多少个4字节。
  • 6位标识位置(TCP Flag ),包的类型,主要用于操控tcp的状态机。(详细内容请看下节)
  • 16位窗口大小(Window), 或者叫Sliding Window滑动窗口大小,对应 滑动窗口机制
  • 16位校验和(checksum)
  • 16位紧急指针 (Urgent Pointer)

这里需要注意的是:

  1. tcp协议包里,是没有IP的。IP在下一层的IP协议里。tcp关注的是端口号,是两个进程间的事。
  2. 一个tcp链接,需要四元祖标识(src_ip, src_port, dst_ip, dst_port)。只有四个属性完全相等时,才能表示为同一链接。

1.2、标识位(Tcp Flag)

  • URG: 标识紧急指针是否有效
  • ACK: 标识确认序号是否有效
  • PSH: 用来提示接收端应用程序立刻将数据从tcp缓冲区读走
  • RST: 要求重新建立连接. 我们把含有RST标识的报文称为复位报文段
  • SYN: 请求建立连接. 我们把含有SYN标识的报文称为同步报文段
  • FIN: 通知对端, 本端即将关闭. 我们把含有FIN标识的报文称为结束报文段

1.3、TCP状态机

网络上的传输是没有连接的,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。
TCP的状态机是一个具有11种状态的有限状态机。

状态机

上图中涉及的11种状态,对应的描述,如下表所示。

状态 描述
CLOSED 关闭状态,没有连接活动或正在进行
LISTEN 监听状态,服务器正在等待连接进入
SYN RCVD 收到一个连接请求,尚未确认
SYN SENT 已经发出连接请求,等待确认
ESTABLISHED 连接建立,正常数据传输状态
FIN WAIT 1 (主动关闭)已经发送关闭请求,等待确认
FIN WAIT 2 (主动关闭)收到对方关闭确认,等待对方关闭请求
TIME WAIT 完成双向关闭,等待所有分组死掉
CLOSING 双方同时尝试关闭,等待对方确认
CLOSE WAIT (被动关闭)收到对方关闭请求,已经确认
LAST ACK (被动关闭)等待最后一个关闭确认,并等待所有分组死掉

介绍完了tcp相关的基本概念,我们继续介绍tcp的运行机制。我将分成两部分来描述,即保障可靠性的相关机制和提高性能的相关机制。

2、保障可靠性

2.1、确认应答机制

tcp协议会将数据的每个字节都标记上编号(序列号)。每次数据传送,都会在报头的seq位,标注上当前传送到了哪一部分(序号表示)。而与之对应的ACK报文都会在ack位上返回上次的seq位上的序号,以表示这部分数据,我收到了。

ack机制

2.2 超时重传机制

确认应答机制基础上,我们知道,如果主机A主机B发送请求(seq=1000),主机B应该返回确认(ack=1001)。但如果因为网络问题,主机A迟迟没有收到主机B的确认。tcp应该如何处理此问题?这就涉及到了超时重传机制
我们继续上面的问题,如果A没有收到B的回信,可能的原因应该有两种:

  1. A->B的信丢了
  2. B->A的信丢了

针对第一种情况,如果A未收到B的回信,一段时间后,A会进行重传。(每次发送出数据后,A就会维护一个计时器,收到确认后重置。)

超时重传1

但是,如果A未收到回信,是因为B->A丢失了,而A仍然重传,那么B端就会收到多个A的重复数据。 怎么办呢?其实利用每次传输的序列号,很容易去重。

超时重传2

2.3、链接管理机制

2.3.1、链接创建(三次握手)

  • tcp服务端会建立TCB(传输控制块)进入Listen状态。
  • tcp客户端也会创建TCB,发送SYN报文(tcp客户端首先会初始化一个自身的序列号x,令seq=x,同时SYN=1。),自身进入SYN-SENT(已经发出连接请求,等待确认)。
  • tcp服务器收到请求链接后,如果同意建立链接,就返回ACK报文确认。(tcp服务器会令ACK=1表示同意,同时根据应答响应机制,会返回一个ack=x+1,同时初始化一个自己的序列号y,seq=y。最后,当前链接仍然在同步状态,所以SYN=1。)自身进入SYN-RCVD状态。
  • tcp客户端收到服务器的确认后,要再次返回一个确认。此时ACK=1,seq=x+1,ack=y+1。信息发出后,自身进入ESTABLISHED状态(链接建立)
  • tcp服务器收到客户端的确认后,进入ESTABLISHED状态(链接建立)。此时,双方就可以传递数据了。

三次握手

建立链接为什么需要三次握手,两次握手不行么?
主要是为了防止失效的报文,突然传递到服务器。导致建立链接,浪费资源。

2.3.2、链接释放(四次挥手)

对于tcp链接,链接的双方都可以释放链接。这里假设双方处于ESTABLISHED状态,客户端发起释放链接。

  • 首先,客户端向服务器发起链接释放报文段,自身进入FIN WAIT 1状态。此时FN=1,seq=u

  • 服务端收到FIN=1的报文段,返回确认(ACK=1,seq=v,ack=u+1),同时自身进入CLOSE-WAIT
    此时,TCP要通知上层应用,客户端到服务器方向的链接中断了。此时TCP处于半关闭状态。
    如果此时服务端还有一些未传完的数据,服务端可以继续传递。

  • 客户端收到服务端确认后,进入FIN WAIT 2状态。此时,客户端仍然会接收服务端发送的数据。直到服务端发完数据,发起释放请求。

  • 服务端发送完数据后,就可以发送FIN报文段释放链接了(FIN=1,ACK=1,seq=w,ack=u+1)。自身就进入了LAST ACK状态,等待客户端的最后确认。

  • 客户端收到服务端的关闭请求后,返回确认(ACK=1,seq=u+1,ack=w+1)。收到确认后,服务端会进入CLOSE状态。

  • 客户端返回确认后,会进入TIME-WAIT状态。注意此时链接并未释放,客户端需要等待2*MSL(最长报文段寿命)后,彻底释放链接。进入CLOSE状态。

四次挥手

为什么最后客户端还要等待 2*MSL的时间?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

  1. 保证客户端发送的最后一个ACK报文能够到达服务器,如果ACK报文丢失,服务端就可以通过上文提到的超时重传机制,重新获取ACK报文。

  2. 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文

2.4、拥塞控制机制

阅读顺序,请先阅读3.1、3.2

滑动窗口机制的前提下,可以大大加快数据传输的速度。但是接收端的数据处理能力是有限度的。如果在不知道接收端的情况下冒然发送大量数据。很可能会出问题(接收端缓冲区填满,引起丢包,重传...)。
tcp引入了慢启动机制,简单的说就是,先发少量数据“探探路”,摸清情况后再决定用什么速度发送数据。 慢启动

这里引入拥塞窗口的概念:

  1. 初始状态下拥塞窗口=1;
  2. 每收到一次ACK,拥塞窗口+1
  3. 每次发送数据时,拥塞窗口 = min(拥塞窗口,接收端主机反馈的窗口)

目前为止拥塞窗口是按照指数增长的。为了控制拥塞窗口的增长速度。tcp协议中又引入了慢启动的阈值(ssthresh)。如下图所示,当拥塞窗口超过阈值时,开始线性增长。

当发生网路拥塞时,阈值=当前拥塞窗口大小/2 ,拥塞窗口=1

注意
关于网络拥塞
少量的丢包,仅会触发超时重传
只有大量的丢包,才会被判定为网络拥塞

慢启动的阈值

2.5、流量控制机制

接收端的数据处理能力是有限度的。如果发送数据太快,将接收端缓冲区填满。就会产生丢包,进而引发超时重传等一系列问题。针对这个问题tcp协议中有流量控制机制

  • 接收端会将自己可以接收的缓冲区大小,通过ACK中的window设置窗口大小,告知发送端。
  • 接收端缓冲区快满时,会将一个更小的值,发送给发送端,发送端就会据此减慢发送的速度。
  • 如果接收端缓冲区已经满了,会将window大小设置为0。发送端接收到ACK后,会停止发送,同时每隔一段时间发一个探测的包,获取最新的接收端window。

流量控制机制

3、提高性能

3.1、滑动窗口机制

在前面章节中,我们提到了确认应答机制(ACK机制),对于每一个发送的数据段,都要返回一个ACK确认应答。收到ACK以后再发送下一个数据段。
这里有一个比较大的缺点,就是性能较差。那可不可以批量发送多个数据段呢?(如下图所示)

滑动窗口

这里提出一个概念:滑动窗口
窗口大小:指无需等待确认应答,既可以直接发送的数据的最大值。上图直接发送了四段数据,窗口大小即为4000字节。 窗口大小标识在tcp报头的window中(在第一章中有图)。

滑动窗口:前n段数据(依据窗口大小)无需等待,之后,每收到一个ACK应答,就继续发送第n+1,n+2,n+3...段数据。这个窗口会不断向后滑动,故称之为“滑动窗口”。

操作系统为了支持滑动窗口,专门开辟了一段缓冲区记录发送的数据段。只有收到ACK的数据段才可以删除。未收到ACK的数据段会一直保存,以备丢包后超时重传

滑动窗口2

3.2、快重传机制(高速重发控制)

在滑动窗口的基础上,如果丢包了怎么办呢?
这里我们跟描述超时重传一样,分两种情况:

  1. 主机A -> 主机B,某个数据段丢失。
  2. 主机B -> 主机A,某个ACK丢失。

对于第一种情况,ACK丢失的问题不大,因为我们可以通过后续的ACK确认到主机B收到了哪些数据段,无需重传。 快重传1

对于第二种情况,即发出的数据段丢失。如下图所示,如果1001-2000数据段丢失,主机B就会一直发送,下一段需要1001的应答。当主机A连续收到三次同样的1001,主机A就会将1001-2000数据段重传。主机B收到1001后,会直接应答7001。这种机制就是快重传。
快重传2

3.3、延迟应答机制

阅读顺序,请先阅读2.4、2.5

接收端主机收到数据后如果立即返回ACK,此时的窗口大小很可能会比较小。 通常情况下,接收端处理数据的速度非常快。我们只要稍等一会,数据也就处理完了,当前的窗口就很可能会变大。

窗口越大, 网络吞吐量就越大, 传输效率就越高。
TCP的目标是在保证网络不拥堵的情况下尽量提高传输效率;

同时,也不是所有数据包,都延迟应答。有两种特殊情况。

  1. 数量限制:每隔N个包,就会直接应答,没有延迟。(通常情况下N=2)
  2. 时间限制:超过最大延迟时间,也会直接应答,没有延迟。(通常情况下,最大延迟时间=200ms)

这就是tcp的延迟应答机制

3.4、捎带应答

在延迟应答的基础上, 我们发现, 很多情况下
客户端和服务器在应用层也是 “一发一收” 的
意味着客户端给服务器说了 “How are you”
服务器也会给客户端回一个 “Fine, thank you”
那么这个时候ACK就可以搭顺风车, 和服务器回应的 “Fine, thank you” 一起发送给客户端

参考文献

扩展