传输层协议TCP(3)

1 TCP连接的收发空间

对于 TCP 的任何一端来说,所谓 TCP 连接,不过是叫作 TCB 的一块内存而已。TCB 这个数据结构,如下图所示:

       上图中,TCB 的主要字段,除了“其他相关变量”,剩余的几个字段的含义,图中已经表达的比较清楚,这里就不再重复解释。但是,用户接收数据指针——指向用户接收数据所在的缓存(其内存资源就是有限的)。为了解决TCP发送数据速率与TCP处理数据速率间的问题,TCP 在其报文头中设计了1个字段“Window”,如下图:

       TCP 报文头中的“Window”字段,占有16个 bits,取值范围是0~65535,其目的就是通知对方自己还能接收多少字节的数据(再多,接收数据的缓存就溢出了),以使对方不要发送超出该数量的数据,如下图所示:

        上图5-39中,在 T0时刻,B 的接收缓存是6000字节,T1 时刻,A 给 B 发送了1000字节,T2 时刻,B 告知 A,它的 Window = 5000(即它还能再接收5000个字节)。图5-39中,还有一个比较有意思的现象:T3时刻,A 向 B 发送了500字节的数据,在此之后,A 并没有等待 B 的 ACK 报文,而是在 T4 时刻又向 B 发送了 600字节的数据。              在 TCP 连接创建(三次握手)时、TCP 连接关闭(四次挥手)时,我们已经习惯了“一问一答”,即TCP 的一方发送了1次“SYN/FIN”报文之后,总在等对方的“ACK”报文。不过这种“一问一答”的方式在 TCP 数据发送阶段,则没有多大必要,而且效率也不高。所以,在图5-39中,我们看到 T3、T4时刻,A 连续发送数据给 B,而不必等待 B 的应答。固然,图5-39中 A 可以连续发送数据给 B,但是对于这些发送的数据,A 一定要在将来的某个时间内收到 B 的 ACK,否则(超时的话),A 还需要重传这些数据。(TCP可靠传输机制)。

       TCP 其实利用报文中的 SEQ(Sequence Number)、AKN(Acknowledgment Number)这两个字段来实现它的可靠性机制的(图5-39为了突出 Window 字段,没有描述这两个字段)。SEQ、AKN、Window 这3个字段通过有效地计算,就构成了 TCP 数据的收发空间。

1.1 TCP数据的发送空间

见下图:

        

图5-40中,数据分为两大部分:已发送数据、未发送数据。

1.1.1 已发送数据

已发送数据,又分为两部分:

  • (1)已发送已确认:这部分数据已经发送,并且已经得到对方的确认(确认收到),那么这部分数据其实只有概念上的意义,实际上完全可以从内存中抹去。
  • (2)已发送待确认:这部分数据已经发送,但是尚未得到对方确认(还不知道对方是否已经收到)。这部分数据必须先缓存起来,如果超过了一定时间仍然没有收到对方确认,那么这部分数据需要重新发送。

       图5-40中那个点“SND.UNA”(点“A”)是 SEND.Unacknowledged 的缩写,它是一个数字,它的含义如图5-41所示:(已发送待确认的报文有多个,SND.UNA 指的就是图5-41中的第1个报文中的 SEQ 字段的值。)

        

1.1.2 未发送数据

未发送数据,也分为两部分:

(1)允许发送数据:“允许”二字,令人困惑。这一切都与对方的接收窗口有关。前文中我们说过,所收到的对方报文的中Window 字段,代表对方最多还能接收多少字节——这个数字,也就是本方当前所能发送的最多字节数,如图5-42所示: 

        

SND.WND 是一个动态变化的数字,因为每次收到的报文里window字段的值大小可能不一样。SND.NXT,它是 SEND.NEXT 的缩写,其含义如下图:

         

SND.NXT 也是一个动态变化的值,它与刚刚发送的报文有关,等于所回报文的 AKN值。上一节里曾经描述过类似的公式,这里再修正一下(伪码):

        

       通过刚刚发送的报文,就能计算出下一个将要发送的报文的 SEQ(SND.NXT),再加上当前的发送窗口 SND.WND,就能确定:用户的待发送数据中,从 SND.NXT 字节开始,到(SND.NXT + SND.WND)字节结束,一共 SND.WND 个字节,是允许被发送的。

(2)未允许发送数据:介绍了那么“允许发送数据”,未允许发送数据就很简单了——用户的待发送数据中,从(SND.NXT + SND.WND +1 )字节开始,以后所有的字节,都不允许被发送。当然,未允许发送数据也是动态变化的。当对方的应答报文中的 Window 字段增大时(对方又处理了一些字节,释放了一些内存,腾出新的空间来接收新的数据),未允许发送的数据的序号,会越来越向后移。

总结一下:

  • (1)用户所需要发送的数据,每一个字节都有1个编号,第1个字节的编号叫 ISS(Initial Send Sequence Number,后面的小节会讲述 ISS 的取值方法),后面字节的编号按顺序加“1”
  • (2)TCP 数据发送空间,是由3个数字组成,这些数字是:SND.UNA、SND.NXT、SND.WND
  • (3)这3个数字,标识了用户所需发送数据的状态:SND.UNA 之前数据,代表“已发送已确认”;SND.UNA~SND.NXT 之间的数据,代表“已发送待确认”;SND.NXT~SND.NXT + WND 之间的数据,代表“允许发送(尚未发送)”;SND.NXT + WND 之后的数据,代表“未允许发送(尚未发送)”。

1.2 TCP 数据的接收空间

如下图:

      

       上图中的 RCV.NXT,是 Receive.Next 的缩写,它表示下一个将要接收报文的 SEQ 应该是多少,它的计算公式,完全等同于上一小节介绍的 SND.AKN,这里就不再重复。上图中的 RCV.WND,是 Receive.Window 的缩写,它表示当前 TCP 连接还能接收多少字节的数据。

       TCP 数据接收空间的含义如下:(1)TCP 数据接收空间是由2个数字组成:RCV.NXT、RCV.WND。(2)这2个数字代表的是对 TCP 所接收报文的 SEQ 的一种判断法则:

  1. 所接收报文的 SEQ 不应该小于 RCV.NXT,因为小于 RCV.NXT 的报文都已经接收并且确认了(回给对方 ACK 报文)。如果真的收到 SEQ 小于 RCV.NXT 的报文,那说明收到重复的报文(收到重复报文该如何处理,后面会描述);
  2. 下一个所接收报文的 SEQ 应该等于 RCV.NXT(如果不等于 RCV.NXT,该如何处理,后面会描述);
  3. 一共还能接收 RCV.WND 个字节的数据。如果所接收报文的数据的长度大于 RCV.WND,则不应该接收(丢弃报文,并且不应该回以 ACK 报文);

1.3 TCB 定义的补充

       本小节的一开始,图5-36对 TCB 的定义中,有这样的描述“其他相关变量”。这些所谓的“其他相关变量”,指的就是 TCP 收发空间相关的变量,再加上 SND.UP 等留待以后再介绍的一些变量,总结如表5-12所示:

       

2 TCP 连接的优先级和安全性

       TCP 的优先级和安全性,是在 IP(的报文头)中描述的。客观地说,TCP 与 IP 的分层和解耦做的并不彻底。TCP 的优先级(precedence)也就是 IP 报文中的优先级,即 IP 报文头中的 ToS 字段的前3个 bits,如下图所示:

       

      TCP 的安全,对应的是 IP 报文头中的可选字段 Security,如下图所示:

    

       用户在创建 TCP 连接时,即在调用 OPEN 接口时,会传入“优先级”和“安全”两个参数。也就是说,TCP 的连接,它其实是有“优先级”和“安全”这两个属性的。当1个 TCP 报文到来时,TCP 会将自身的这两个属性与 TCP 报文(实际上是 IP 报文头)中的两个相应字段做比较,如果“合法”,才会做进一步的处理,否则会转向错误处理分支。

       所谓“合法”,一般原则是:

  • (1)如果所接收的报文中的“precedence/security/compartment”与 TCP 连接中对应的值完全想等,则合法;
  • (2)如果如果所接收的报文中的“precedence/security/compartment”小于 TCP 连接中对应的值,则合法;
  • (3)如果如果所接收的报文中的“precedence/security/compartment”大于 TCP 连接中对应的值:(A)如果用户允许,则也是合法,并且将 TCP 连接对应的值修改为所接收报文中的值;(B)如果用户不允许,则是非法。(所谓用户允许与不允许,是只用户调用 OPEN 接口时所传入了“允许”的参数或者“不允许”的参数)

     接收到非法的“precedence/security/compartment”的报文,TCP 的处理原则就是 发送 RST(Reset)报文。下面讲一下RST报文。

TCP 的 RST 报文

     TCP 的 RST(Reset)报文,其本身倒是比较简单,就是 TCP 报文头中的 Flags 字段中的 R(Reset)标志位取值为“1”,如图5-47所示:

    

       对于 TCP 连接而言,RST表示清零的含义,就是关闭连接。这句话也不是绝对精确。有几种情况:

  • 对于处于 LISTEN 状态的 TCP 连接来说,它收到了这个炸弹,镇定自若,一笑而过,丢弃该报文,并且仍然是处于 LISTEN 状态。因为此时它还处于 LISTEN 状态,还没有建立连接,也就无所谓关闭,也就不需要关闭。
  • 如果一个连接处于 SYN-RECEIVED 状态,并且它前一个状态是 LISTEN 状态,那么它收到 RST 报文时,也是丢弃该报文,并且回到 LISTEN 状态。如果它前一个状态不是 LISTEN 状态,那么它收到 RST 报文时,就会 Abort 该连接,并且状态转移到 CLOSED。
  • 对于其他状态(既不是 LISTEN,也不是 SYN-RECEIVED)的连接,收到 RST 报文后,都会 Abort 该连接,并且状态转移到 CLOSED。当然,对于原本就处于 CLOSED 状态的 TCP 连接来说,它收到 RST 报文直接丢弃就可以了,也不需要状态转移,因为它的状态本来就是 CLOSED。

      有一点需要强调,以上所说的 TCP 连接收到 RST 报文时的行为,有一个前提,那就是 RST 报文是“合法”的。这里所谓的“合法”也跟 TCP 连接当是的状态有关:

  • (1)对于除了 SYN-SENT 状态以外的其他连接,其所收到的 RST 报文的 SEQ(Sequence Number)需要在自己的接收窗口之内(接收窗口的概念,会在5.3节讲述,这里暂且不用追究细节)。
  • (2)对于 SYN-SEND 状态的 TCP 连接,其所收到的 RST 报文,其 ACK 标志必须为“1”。
  • (3)补充一点,以上状态不包括 CLOSED 状态。对于 CLOSED 状态的 TCP 连接来说,从某种意义上讲,所有收到的报文,都是非法的(下文还会继续描述 CLOSED 状态的连接,收到报文的处理情况)。

    何时发送 RST 报文,与 TCP 连接的状态有关。大致也有如下几种情况:

  • 对于 CLOSED 状态的 TCP 连接来说,收到所有的报文它都会丢弃。除了丢弃,如果所收到的报文不是 RST 报文,那么 TCP 协议栈还会给对方回一个 RST 报文。
  • 对于非 CLOSED 状态的 TCP 连接而言,发送 RST 报文的理由,都与“precedence/security/compartment”有关。

       对于同步状态的 TCP 连接来说——RFC 793 把 ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT 等七种状态称为同步状态(synchronized state),其实也就是 TCP 连接建立(ESTABLISHED)以及其后的状态————如果收到 SEQ 超出接收窗口外或者 AKN 错误的 TCP 报文,它们反而不会发送 RST 报文,只是默默地发送一个空的 ACK 报文(只有报文头,不包含数据),报文中指明当前它当前的 SEQ(潜台词也就是它所期望的接收报文中的 AKN,也就说,序号错了没有关系,咱可以重新校正)。

       但是,对于同步状态的 TCP 连接来说,如果所接收报文中的“precedence/security/compartment”与其自身的对应的值不匹配(不想等),那么毫不客气地回以一个 RST 报文,并且转移到 CLOSED 状态。

       对于非同步状态的 TCP 连接来说——RFC 793 把 LISTEN、SYN-SENT、SYN-RECEIVED 三种状态称为非同步状态(non-synchronized state),其实也就是 TCP 连接建立(ESTABLISHED)之前的状态——它所面对“precedence/security/compartment”的态度,比同步状态的 TCP 连接,要复杂一些。

  • 首先,它要求所接收报文的“security/compartment”要与自己连接的相对应的值完全匹配(相等),否则就发送 RST 报文。
  • 其次,它对于“precedence”的态度,则有所区别。不过这种区别描述起来相当苦涩,不易于理解,我们还是用一个表格来表述,如下表所示:

       

4 TCP 连接状态机的进一步阐述

      TCP 连接所面临的场景有:

  • (1)用户调用 TCP 接口
  • (2)一方等待另一方 TCP 报文
  • (3)一方收到另一方的 TCP 报文

       在这些场景中,除了上一小节(TCP 连接的状态机)所描述的“经典”流程,还有其他情形、其他细节需要进一步阐述。比如用户调用 TCP 接口,这是用户自己的决定,他可以在任意时刻调用任意接口,对于 TCP 来说,有的调用是“合法”的,有的调用是“非法”的——合法会怎么处理,非法会怎么处理?再比如,TCP 的一方发送报文给另一方时,它会等待对方的应答。但是,如果对方没有应答呢?再比如,TCP 一方收到另一方的报文时,如果报文是“非法”的,它又应该怎么处理?

      下面我们就分别阐述这些场景的细节:

      用户调用 TCP 接口,具体来说,就是用户(人)所编写的程序,调用 TCP 协议栈的编程接口。TCP 的编程接口有:OPEN、SEND、RECEIVE、CLOSE、ABORT、STATUS。这些接口的基本含义,如下表所示:

     

       上表中可以看到,TCP 的接口对用户封装了很多细节,比如打开连接、关闭连接,就封装了它们背后的三次握手、四次挥手等。上表所说的是 TCP 各个接口的基本含义,或者说是正常的处理流程。但是当 TCP 连接处于不同的状态时,用户调用不同的接口,TCP 会有不同的反应:有时候是合法调用(即正常处理),有时候是非法调用(TCP 会返回错误)。下面我们详细讲述每个接口在不同状态下的调用情况:

1)调用 OPEN 接口

2)调用 SEND 接口

3)调用 RECEIVE 接口

4)调用 CLOSE 接口

5)调用 ABORT 接口

6)调用 STATUS 接口

等待对方报文

      一方等待另一方的 TCP 报文,如果在规定时间内等到对方的报文,那么就按照“正常”的流程往下走,如果没有等到,则意味着超时。超时也分为3种情形:TCP 连接创建时、TCP 连接关闭时、TCP 数据传输时。第3种情形(TCP 数据传输时)留待下一节讲述,本小节只讲述前两种情形。

      TCP 创建连接的“三次握手”,从报文分类的角度,也可以“分解”为“四次握手”,如下图所示:

      

      图5-48将原来三次握手(请参见图5-30)中的第2次握手一分为二,从而分解为四次握手。图5-48还是有点复杂,我们继续将其抽象,如图5-49所示:

       

       上图中有两处等待时间——两处等待时间都是一个意思——TCP 的一方发送 SYN 请求时,等待另一方的 ACK。 TCP 也不能无休止的等下去,它总有一个超时时间。更加抽象地说,只要是请求报文,TCP 就在等一个应答确认(ACK)报文。而在 TCP 的世界里,有等待就有超时。这不仅体现在 TCP 连接的创建,也体现在连接的关闭,如图5-50所示:

        

        图5-50(关闭连接),“1”和“3”两个等待点,与图5-37(创建连接)的两个等待点(“1”和“3”)本质上是一样的,都是1个请求报文在等待1个应答确认(ACK)报文。只不过关闭连接的请求报文是 FIN,创建连接的请求报文是 SYN。

       图5-50比图5-49还多了两个等待点:等待点“2”是 A 在等待 B 发送 FIN 报文(关闭连接请求);等待点“4”是 A 在等待 2MSL 时间,然后关闭自己。不过等待点“4”是 TCP 固有设计,不能算作异常处理。TCP 的连接是相互的,A 向 B 请求关闭了连接之后,它还得等待 B 也向它请求关闭连接——双方都关闭以后,TCP 连接才认为是关闭了。这是等待点“2”的真正含义。同理,TCP 连接的创建,也应该有类似一个等待点。只不过在创建连接时,TCP 将 B 的确认与请求报文合二为一,所以我们在图5-37中没有看到那个对应的等待点。

       TCP 连接的创建和关闭,所涉及的等待点,如下图所示:

       

图5-51所描述的等待点有两类:

  • (1)“请求-确认”等待点,一方发送完 SYN/FIN 请求,等待另一方应答确认。
  • (2)“关闭连接”等待点,一方处于 FIN-WAIT-1 状体,等待另一方发送 FIN 请求。

有等待的地方,就有超时。关于这两类等待点,TCP 是这样处理的:

  • (1)超时时间,可以由用户(TCP 的实现者、TCP 的使用者)自行设置。
  • (2)超时以后,其结果都是关闭连接(删除相应的 TCB)。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值