Chinaunix首页 | 论坛 | 博客
  • 博客访问: 409822
  • 博文数量: 403
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: -70
  • 用 户 组: 普通用户
  • 注册时间: 2016-09-05 12:45
文章分类

全部博文(403)

文章存档

2014年(3)

2013年(1)

2012年(3)

2011年(21)

2010年(13)

2009年(64)

2008年(9)

2007年(36)

2006年(253)

分类: 系统运维

2006-11-23 10:38:22

作者:dlmu2001

RFC793中文翻译三

3.功能性规范(FUNCTIONAL SPECIFICATION)
3.1 头部格式
TCP分片作为internet数据报发送。Internet协议头部携带了一些信息头部,包括源主机地址和目的主机地址[2]。TCP头部也仿效Internet头部,提供TCP协议的一些特定信息。这种区分考虑了除了TCP外的主机级别协议的存在。

TCP头部格式



0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                            TCP Header Format

          Note that one tick mark represents one bit position.

                               Figure 3.


源端口(Source Port):16 bits

源端口号码

目的端口(Destination Port):16 bits

目的端口号码

系列号(Sequence Number):32 bits

本分片的第一个数据八位字节的系列号码(除当SYN出现时外)。如果出现SYN标志,系列号是初使系列号(initial sequece:ISN),且第一个数据八位字节是ISN+1.

确认号码(Acknowledgment Number):32 bits

如果设定了ACK控制位,则这个头部包含了分片接收者期待接收的下一个系列号码。一旦连接建立,这个头部就总是发送。

数据偏移(Data Offset): 4 bits,TCP首部长度

TCP头部中32bit双字(words)的数目。指示了数据从哪里开始。TCP头部(即使是包含选项的头部)是32bits长度的整数号码。

保留(Reserved):6 bits

保留以后使用。必须是0值。

控制位(Control Bits):6 bits(从左到右):

URG:紧急指针字段有效(Urgent Pointer field significant)

ACK:确认头部字段有效(Acknowledgment field significant)

PSH:强制函数(Push Function)

RST:重置连接(Reset the connection)

SYN:同步系列号码(Synchronize sequence numbers)

FIN:再没有来自发送者的数据(No more data from sender)

窗口(Window):16 bits

接收端正准备接收的数据八位字节的数目,开始于确认字段(acknowledgment)指示的位置。

校验和(Checksum):16 bits

在头部和文本中的所有16 bit字的补偿总和。如果分片包含一个0值的头部和文本八位字节要检验,为校验用最后一个八位字节右边填充0值以构成一个16 bit的字。填充不作为分片的一部分传送。当计算校验和的时候,校验和字段自己被0代替。

校验和也包括TCP头部之前的伪头部。这些伪头部包括源地址,目的地址,协议和TCP长度。这可以避免报文被错误地路由。这些信息在Internet协议中携带,在TCP/Network接口的参数中传递,或者是TCP调用IP的返回值。

                     +--------+--------+--------+--------+
                     |           Source Address          |
                     +--------+--------+--------+--------+
                     |         Destination Address       |
                     +--------+--------+--------+--------+
                     |  zero  |  PTCL  |    TCP Length   |
                     +--------+--------+--------+--------+
TCP长度是TCP头部加上数据长度的八位字节数(这不是一个明确传输的数量,但是被计算),且它不计入12个八位字节的伪头部。

紧急指针(Urgent Pointer):16 bits

该字段传达了紧急指针的当前值,是该分片里面从系列号码开始的正偏移。紧急指针指向根据紧急数据后面的八位字节的系列号码。该头部只有当URG控制位设置时才有效。

选项(Options):可变

选项位于TCP头部后面,长度上是8 bits的整数倍。所有选项包含在校验和中。选项可以开始于任何八位字节巴结。选项的格式有两种情况:

1:单独的选项类型(option-kind)的八位字节

2:选项类型的八位字节,选项长度的八位字节,以及真正的选项数据字节。

选项长度(option-length)计入了选项类型(option-kind),选项长度(option-length)以及选项数据(option-data)。

注意选项列表可能比数据偏移字段暗示的短。超过End-of-Option选项的头部的内容必须进行填充。

TCP必须实现所有的选项

当前定义的选项包括:

类型             长度            意义

0                -----             选项列表的结束

1                -----             无操作

2                4               最大分片大小

特定选项定义:

选项列表的结束(End of option list)

+--------+
        |00000000|
        +--------+
         Kind=0
选项代码指示了选项列表的结束。这可能同根据数据偏移字段得到的TCP头部不一致。这个选项用在所有选项的结束,而不是每个选项的结束。且仅在选项的结束同TCP头部的结束不一致的情况下需要使用

无操作(No Operation):

        +--------+
        |00000001|
        +--------+
         Kind=1
该选项代码可以在选项之间使用,比如,为了在一个字边界上对齐接下来的选项的开始。不保证发送者使用这个选项,所以接收者必须准备处理没有在一个字边界对齐的选项。

最大分片大小(Maximum Segment Size)

        +--------+--------+---------+--------+
        |00000010|00000100|   max seg size   |
        +--------+--------+---------+--------+
         Kind=2   Length=4
最大分片大小选项数据(Maximum Segment Size Option Data):16 bits

如果这个选项存在,则其指示了发送这个分片的TCP的最大接收分片。这个字段必须仅在初始化连接请求阶段发送(比如,在SYN 控制位设置的分片)。如果不使用这个选项,则允许任意大小的分片。

填充(Padding):可变

3.2 术语(Terminology)
在深入探讨TCP的操作之前,我们需要详细介绍一些术语。TCP连接的维持要求记住一些变量。我们设想这些变量存储在一个连接记录中,称这个连接记录为传输控制块(Transmission Control Block :TCB)。在存储在TCB的变量中,有本地和远端socket编号(local and remote socket numbers),安全(security)和连接优先级(precedence of connection),用户发送和接收缓冲的指针,重传队列和当前分片的指针。另外还有一些同发送和接收系列号相关的变量存储在TCB中。

发送系列号变量

SND.UNA - 发送 未经确认(send unacknowledged)

SND.NXT - 发送下一个(send next)

SND.WND - 发送窗口(send window)

SND.UP  - 发送紧急指针(send urgent pointer)

SND.WL1 - 供最后窗口更新的分片系列号(segment sequence number used for last window

update)

SND.WL2 - 供最后窗口更新的分片确认号码(segment acknowledgment number used for last

             Window update)

ISS   - 初始发送系列号(initial send sequence number)

接收系列号变量

RCV.NXT - 接收下一个(receive next)

RCV.WND - 接收窗口(receive window)

RCV.UP - 接收紧急指针(receive urgent pointer)

IRS  - 初始接收系列号(initial receive sequence number)

下面的图可以帮助你将这些发送系列号空间的变量联系起来。

发送系列号空间

                   1         2          3          4      

              ----------|----------|----------|----------

                     SND.UNA    SND.NXT    SND.UNA        

                                          +SND.WND   

1 - 已经确认过的老的系列号

2 - 未确认过的数据的系列号

3 - 新数据传送的系列号(sequence numbers allowed for new data transmission)

4 - 当前不允许传送的将来的系列号

发送窗口是图中3所标注的空间

接收系列号空间:

                       1          2          3      

                   ----------|----------|----------

                          RCV.NXT    RCV.NXT        

                                    +RCV.WND        

1 - 已经确认的老系列号

2 - 新接收的系列号(sequence numbers allowed for new reception)

3 - 现在不允许的将来的系列号(future sequence numbers which are not yet allowed)

接收窗口是图中2所标注的空间

还有一些变量经常使用,它们是从当前分片的字段中取值的。

当前分片变量

SEG.SEQ - 分片系列号(segment sequence number)

SEG.ACK - 分片确认号码(segment acknowledge number)

SEG.LEN - 分片长度(segment length)

SEG.WND - 分片窗口(segment window)

SEG.UP - 分片紧急指针(segment urgent pointer)

SEG.PRC -分片优先级值(segment precedence value)

连接过程在生存时间内经过一系列的状态。LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT,和最后的虚构状态CLOSED。CLOSED是虚构的因为处于CLOSED状态的时候已经没有TCB,也就是说没有连接。下面是这些状态的简单意义:

LISTEN - 等待从任何远端TCP和端口的连接请求

SYN-SENT -发送完一个连接请求后等待一个匹配的连接请求

SYN-RECEIVED - 发送连接请求并且接收到匹配的连接请求以后等待连接请求确认

ESTABLISHED - 表示一个打开的连接,接收到的数据可以被投递给用户。连接的数据传

                 输阶段的正常状态。

FIN-WAIT-1 - 等待远端TCP的连接终止请求,或者等待之前发送的连接终止请求的确认

FIN-WAIT-2 - 等待远端TCP的连接终止请求

CLOSE-WAIT - 等待本地用户的连接终止请求

CLOSING - 等待远端TCP的连接终止请求确认

LAST-ACK - 等待先前发送给远端TCP的连接终止请求的确认(包括它字节的连接终止

              请求的确认)

TIME-WAIT - 等待足够的时间过去以确保远端TCP接收到它的连接终止请求的确认

CLOSED - 不在连接状态

TCP连接响应不同的事件从一个状态过渡到另一个状态。事件是用户调用,OPEN,SEND,RECEIVE,CLOSE,ABORT,和STATUS;到来的分片,特别是那些包含SYN,ACK,RST和FIN标志的分片;超时。

下图仅展示了状态变化,及导致变化的事件和引起的行为,但是未连接的错误情况和行为不包含在内。在后面的章节,将提供更详细的描述。

注:该图仅是摘要,不能当作所有的规范。


                              +---------+ ---------\      active OPEN  
                              |  CLOSED |            \    -----------  
                              +---------+<---------\   \   create TCB  
                                |     ^              \   \  snd SYN   
                   passive OPEN |     |   CLOSE        \   \           
                   ------------ |     | ----------       \   \         
                    create TCB  |     | delete TCB         \   \      
                                V     |                      \   \     
                              +---------+            CLOSE    |    \   
                              |  LISTEN |          ---------- |     |  
                              +---------+          delete TCB |     |  
                   rcv SYN      |     |     SEND              |     |  
                  -----------   |     |    -------            |     V  
+---------+      snd SYN,ACK  /       \   snd SYN          +---------+
|         |<-----------------           ------------------>|         |
|   SYN   |                    rcv SYN                     |   SYN   |
|   RCVD  |<-----------------------------------------------|   SENT  |
|         |                    snd ACK                     |         |
|         |------------------           -------------------|         |
+---------+   rcv ACK of SYN  \       /  rcv SYN,ACK       +---------+
   |           --------------   |     |   -----------                  
   |                  x         |     |     snd ACK                    
   |                            V     V                                
   |  CLOSE                   +---------+                              
   | -------                  |  ESTAB  |                              
   | snd FIN                  +---------+                              
   |                   CLOSE    |     |    rcv FIN                     
   V                  -------   |     |    -------                     
+---------+          snd FIN  /       \   snd ACK          +---------+
|  FIN    |<-----------------           ------------------>|  CLOSE  |
| WAIT-1  |------------------                              |   WAIT  |
+---------+          rcv FIN  \                            +---------+
   | rcv ACK of FIN   -------   |                            CLOSE  |  
   | --------------   snd ACK   |                           ------- |  
   V        x                   V                           snd FIN V  
+---------+                  +---------+                   +---------+
|FINWAIT-2|                  | CLOSING |                   | LAST-ACK|
+---------+                  +---------+                   +---------+
   |                rcv ACK of FIN |                 rcv ACK of FIN |  
   |  rcv FIN       -------------- |    Timeout=2MSL -------------- |  
   |  -------              x       V    ------------        x       V  
    \ snd ACK                 +---------+delete TCB         +---------+
     ------------------------>|TIME WAIT|------------------>| CLOSED  |
                              +---------+                   +---------+

                      TCP Connection State Diagram
                               Figure 6.

3.3 系列号(Sequence Numbers)
设计上的一个基本观点是在一个TCP连接上发送的每个八位字节的数据都有一个系列号码。因为每个八位字节是编过序号的,所以每个都可以被确认。所使用的确认机制是累积的,所以序号X的确认指示的是所有X之前但不包括X的数据已经收到了。这种机制在重传中允许用来作为直接的复制检测。在一个分片内的八位字节的编号机制是紧跟头部之后的第一个数据八位字节是最小编号的,接下来进行顺序编号。

需要记住的是实际的系列号码空间是有限的,但是是很大的。该空间从0到2**32-1。因为空间是有限的,所有的处理系列号的算法必须执行模2**32。当系列号从2**32-1循环到0的时候,算法保留系列号的关系。计算模算法有些微妙,必须在比较这些值的编程的时候谨慎考虑。符号“=<“表示”小于或者等于“(模2**32)。

TCP必须执行的典型的一种系列号比较包括:

(a)       确定一个确认指向的是有些系列号码已经发送但是未经确认

(b)       确定一个分片的所有系列号码被确认(比如,用以将分片从重传队列中移除)

(c)       确定到来的分片包含了期望的分片(比如,分片同接收窗口交迭)

作为发送数据的响应,TCP会收到确认(acknowledgements)。在处理确认的时候需要做如下比较:

SND.UNA = 最老的未确认的系列号

SND.NXT = 下一个要发送的系列号

SEG.ACK =接收TCP发送过来的确认(接收TCP期望的下一个系列号)

SEG.SEQ = 分片的第一个系列号

SEG.LEN = 分片中数据占有的八位字节号码(包括SYN和FIN)

SEG.SEQ+SEG.LEN-1 = 分片的最好一个系列号

一个新的确认(称为“可接受的ack”),遵循下面的不等式:

SND.UNA
如果重传队列中的一个分片的系列号和长度的和小于或者等于到来分片中的确认的值,则该分片被完全确认。

收到数据的时候,需要进行下面的比较:

RCV.NXT = 在到来分片中期待的下一个系列号,且是接收窗口的左或下边缘

RCV.NXT+RCV.WND-1 = 到来分片中期待的最后一个分片,且是接收窗口的右或上边缘

SEG.SEQ = 到来分片占据的第一个系列号

SEG.SEQ+SEG.LEN-1 = 到来分片占据的最后一个系列号

一个分片被认为用来占据合法系列空间的一部分,如果:

RCV.NXT =
或者

RCV.NXT=
第一部测试是检查分片的开始部分是否在窗口内,第二部测试是检查分片的结尾是否在窗口内,如果分片通过了这两步测试,则它包含了窗口内的数据。

实际情况要比这复杂。由于零窗口和0长度分片的存在,到来分片的接收有4种情况:

    Segment Receive  Test

    Length  Window

    ------- -------  -------------------------------------------



       0       0     SEG.SEQ = RCV.NXT



       0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND



      >0       0     not acceptable



      >0      >0     RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND

                  or RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND

注意当接收窗口为0的时候,除了ACK分片外的其它分片都不被接受。因此,TCP在传输数据和接收ACKs时维护一个0接收窗口是可能的。但是,即使当接收窗口是0,TCP必须处理所有到来分片的RST和URG字段。

初始化系列号选择

我们也利用编号机制来保护某些控制信息。这是通过在系列号空间中明显地包含一些控制标志让这些分片可以无冲突地被传输和确认来实现的(比如,一个且只有一个控制的拷贝被遵循)。控制信息在物理上不在分片数据空间携带。因此,我们必须采用暗中分配系列号给控制信息的规则。SYN和FIN是要求这个保护的控制信息,且这些控制信息仅在连接打开和关闭的时候使用。为了系列号的用途,SYN被认为出现在它出现的分片的第一个真实数据字节之前,而FIN被认为出现在它出现的分片的最后一个字节之后。分片长度包含数据和控制信息占据的系列号空间。当SYN出现的时候,SEG.SEQ是SYN的系列号。

协议不限制一个特定的连接被一次又一次的使用。连接被定义成一对socket。一个连接的新实例将当成连接的化身。这就引起了问题“TCP如何从之前连接化身的分片区分出复制分片”。如果连接关闭后被快速地打开,或者当连接由于内存丢失而断开然后重建,这个问题就变得很明显。

为了避免混淆,必须防止连接的一个化身的分片当同样的系列号存在于更早的化身的网络上的情况下被使用。我们要确保这点,即使TCP崩溃,丢失了他使用过的系列号码的所有信息。当新的连接建立的时候,初始化系列码(intitial sequence number :ISN)产生器被调用,该产生器选择了新的32位的ISN。该系列码产生器一定要有(可能是虚构的)个32位时钟,时钟的低位是每4微妙增长。也就是说,ISN大概每4.55个小时循环一次。因此我们假定分片不会在网络上停留超过最大分片生命周期(Maximum Segment Lifetime:MSL),且MSL小于4.55个小时,这样,我们就有理由假定ISN是独一无二的。

每个连接有一个发送的系列号和一个接收系列号。初始的发送系列号(ISS:initial send sequence number)由发送数据的TCP选择,初始的接收系列号(IRS:initial receive sequence number)在连接建立阶段得到。

一个连接要建立或者初始化,两个TCPs必须在双方的初始化系列号上同步。这是通过携带称为SYN(同步用)的控制位和初始化系列号的连接建立分片的交换完成了。作为一个速记标识,携带SYN位的分片也称为”SYNs”。然后,解决方案需要一个适宜的机制选择初始系列号以及细微地参与交换ISN的握手过程。

同步需要每一端发送它自己的初始化系列号,且从另一端通过ACK接收确认。每一端也必须接收另一端的初始化系列号并且发送一个确认ACK

1)AàB   SYN 我的系列号是X

2)AßB   ACK你的系列号是X

3)AßB   SYN 我的系列号是Y

4)AàB   ACK你的系列号是Y

因为步骤2和3可以结合在一条消息里面,所以这个工程称为3次握手。

因为系列号不依赖于一个网络中的全局时钟,所以三次握手是需要的,TCPs可以有不同的机制来挑选ISN。第一个SYN的接收者无法知道分片是否是个旧的延迟的分片,除非它记得上次用于连接的系列号(这往往是不可能的),因此它必须要发送者验证这个SYN。三次握手以及时钟驱动机制的优点在[3]中会进行讨论。

知道什么时候保持静止

为保证TCP不会产生一个携带了保留在网络中的老的分片的系列号的分片,TCP如果是从一个崩溃中启动或者恢复必须在一个最大分片生命周期内保持静止,在这个周期内,在使用的系列号内存被丢弃,这个周期之后才可以分配任何系列号。本规范设定MSL为2分钟。这是个工程上的选择,如果经验指示它需要做出修改他就可以修改。注意如果TCP被在某种意义上重新初始化,却仍然保留在使用的系列号内存,那么它不需要等待,它仅需保证使用大于那些刚被使用过的系列号码。

TCP静止时间概念(The TCP Quiet Time Concept)

规范规定那些崩溃(crash)且未能保持任何在每个活动(而不是关闭的)连接传输的系列号的信息的主机必须延迟发送任何TCP分片,这个延迟至少是在主机作为一部分的internet系统上经过协议的最大分片生命周期(MSL)。在下面的段落中,将给出规范的解释。TCP实现者可以违反“静止时间”限制,但是有可能导致某些老数据被internet系统上的某些接收者当作新数据接收或者新数据被接收者当作老的复制分片拒绝的风险。

每次形成一个分片然后进入在源主机的网络输出队列,TCPs消耗了系列号空间。TCP协议的复制检测和系列号算法依赖于分片数据同系列号空间的唯一绑定关系,假定系列号在绑定于该系列号的分片被投递和确认且所有复制拷贝已经在internet上消失之前不会循环了所有了2**32的值。如果没有这个假设,两个不同的分片可能被分配了一个同样的或者重叠的系列号,导致接收者对哪个数据是新的哪个数据是老的产生混淆。每个分片会被分配一串连贯的系列号,跟他们分片中的八位字节数目一样。

正常情况下,TCP会记录下一个要发送的系列号和最老的等待确认的分片的系列号,这样子可以避免错误地使用一个它的第一次使用还未被确认的系列号。仅仅这样并不能保证老的重复数据已经在网络上消失,因此系列号空间需要足够大以减少闲置重复分片到来导致的麻烦的可能性。在2兆/秒情况下,需要4.5个小时才能用光2**32个八位字节的系列号空间。由于网络上的最大分片生命周期不太可能超过几十秒,因此这被认为对可以预见的网络的足够保护,即使数据传输率上升到10兆/秒。在100兆/秒的条件下,循环时间是5.4分钟,这看起来有点短,但仍然在合理范围内。

但是,如果一个源TCP不记得它前次在一个给定连接上使用的系列号的话,TCP中的基本的重复分片检测和系列号算法可能被击败。比如,如果TCP以系列号0开始所有的连接,那么在崩溃或者重启的时候,一个TCP可能重新形成了一个较早的连接(可能是在半打开连接解决方案(half-open connection resolution)之后),且发送了系列号等于或者覆盖在同一个连接的较早化身上的系列号码的包。在不知道使用于一个特定连接的系列号信息的情况下,TCP规范建议源主机在发送分片之前延迟MSL的时间,以让那么较早连接化身发出的分片有时间从系统上消失。

即使主机能够记住时间并且用它来确定初始系列号值,也不能确保没有这个问题(比如,即使时间用来确定每个新的连接化身的初始系列号值)。

比如,假设一个连接以系列号S打开。假定这个连接没有怎么使用,最后初始化系列号函数(ISN(t))采用了一个值S1,这个S1是TCP在一个特定的连接上发送的最后一个分片。现在假定在这个时候,主机崩溃,恢复,然后建立了该连接的一个新化身。初始系列号是S1=ISN(t),刚好是连接的老化身上使用的最后一个系列号!如果恢复足够快速,在产生系列号的网络上任何S1相邻的重复分片都可能到来且被连接的新化身接收者视为新的数据包。

处理这个问题的一种方法是在从崩溃中恢复后特意地延迟发送分片一个MSL的时间,这就是“静止时间”规范。那些想避免等待且乐于接受老数据包和新数据包可能在目的主机产生混淆的风险的主机可以选择不等待“静止时间”。实现者可以提供TCP用户选择在以连接为基础的连接是否在崩溃或等待一段时间的能力,或者可以非正式的对所有连接实现“静止时间”。显然,即使一个用户选择“等待”,主机也并不一定要等待MSL这么长的时间。

总结:每个发送的分片在系列号空间中占据了一个或者多个系列号,被一个分片占用的号码

在过去MSL时间之前都是“忙”或者“在用”,崩溃的时候,一块系列号空间被最后发送的分片的八位字节占用,如果新的化身太块启动且使用了同一个连接的前一个化身的最后分片的系列号空间范围内的系列号,这些潜在的系列号空间覆盖可能导致接收者产生混淆。

3.4 建立一个连接
“三次握手”“是用来建立一个连接的程序。这个程序一般是由一个TCP发起,另一个TCP响应。如果两个TCP同时发起该程序,也可以工作。当同时尝试发起产生的时候,一个TCP在发送了一个“SYN”分片以后接收到一个没有携带确认的“SYN”分片。当然,一个老的重复的“SYN”分片的到达也可能使这种情况发生。正确的“reset”分片的使用可以消除这种情况下的歧义。

下面是一些连接发起的例子。虽然这些例子没有展示使用携带数据的分片的连接同步,这是完全合法的,只要接收TCP没有在清楚的知道数据是合法之前将数据投递给用户(比如,数据必须在接收者的缓冲上进行缓存直到连接到达ESTABLISHED状态)。三次握手降低了错误连接的可能性。这是实现者在内存和提供检查信息的消息之间的一个平衡。

最简单的三次握手入下图所示。图中,每条线为引用方便被编号。右箭头(à)表示TCP分片从TCP A到TCP B的离开,或者从A到B的到达。左箭头(ß)相反。省略号(…)表示仍然停留在网络上(延迟)的分片。“XXX”表示丢失或者被拒绝的分片。注释出现在圆括号中。TCP状态代表了分片(内容在每条线中间显示)离开或者到达后的状态。分片内容以缩略形式表示,包括系列号,控制位和ACK字段。其它字段如窗口,地址,长度和文本被忽略。

      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN

  2.  SYN-SENT    -->                --> SYN-RECEIVED

  3.  ESTABLISHED <--   <-- SYN-RECEIVED

  4.  ESTABLISHED -->        --> ESTABLISHED

  5.  ESTABLISHED --> --> ESTABLISHED

          Basic 3-Way Handshake for Connection Synchronization

                                Figure 7.


在上图的线2中,TCP A通过发送一个指示它将使用100开始的系列号码的SYN分片开始。在线3中,TCP B发送了一个SYN和它从TCP收到的分片的确认。注意,确认字段指示了TCP B现在期望侦听系列号101,确认占用系列号100的SYN。

在线4中,TCP A以包含TCP‘s的SYN包的ACK的空分片响应,而在线5,TCP A发送了一些数据。注意在线5中的系列号同线4中的系列号一致,因为ACK并不占用系列号空间(如果占用,我们将结束正在确认的ACK)。

同时发起相对复杂一些,在现图中展示。每个TCP循环从CLOSED到SYN-SENT到SYN-RECEIVED到ESTABLISHED。

     TCP A                                            TCP B

  1.  CLOSED                                           CLOSED

  2.  SYN-SENT     -->               ...

  3.  SYN-RECEIVED <--               <-- SYN-SENT

  4.               ...               --> SYN-RECEIVED

  5.  SYN-RECEIVED --> ...

  6.  ESTABLISHED  <-- <-- SYN-RECEIVED

  7.               ...      --> ESTABLISHED

                Simultaneous Connection Synchronization

                               Figure 8.
三次握手的基本原则是防止老的重复连接发起导致的混乱。为了处理这个,一条特殊的控制信息,reset,被提了出来。如果正在接收的TCP正处于一个非同步状态(比如,SYN-SENT,SYN-RECEIVED),它在接收到一个可以接受的reset后返回继续监听。如果TCP处于同步状态(ESTABLISHED,FIN-WAIT-1,FIN-WAIT2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT),它放弃了连接且通知用户。我们后面会讨论这种处于“半打开(half-open)”连接下的情况。

      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN

  2.  SYN-SENT    -->                ...

  3.  (duplicate) ...                --> SYN-RECEIVED

  4.  SYN-SENT    <--   <-- SYN-RECEIVED

  5.  SYN-SENT    -->                --> LISTEN

  6.              ...                --> SYN-RECEIVED

  7.  SYN-SENT    <--   <-- SYN-RECEIVED

  8.  ESTABLISHED -->       --> ESTABLISHED

                    Recovery from Old Duplicate SYN

                               Figure 9.


作为一个从老的重复分片中恢复的简单例子,看下图9。在线3,一个老的重复SYN到达TCP B。TCP B不能断定这是一个老的重复分片,所以它正常响应(线4)。TCP A检测到ACK字段不正确就返回了一个RST(reset),该RST的SEQ字段使分片可信。TCP B在收到RST后,返回到LISTEN状态。当原来的SYN在线6最后到达,同步过程正常开始。如果线6的SYN在RST前到达,则将发生更复杂的交换(两个方向都发送RST)。

半打开(Half-Open)连接和其它不规则情况

一条已经建立的连接当TCP的一方已经在自己一端关闭或者中断连接且不知道另一端的情况,或者当连接双方由于崩溃导致失忆变成不同步,就称为“半打开”的连接。如果尝试在该连接的任何一个方向上发送数据,这个连接就会自动变成reset。但是,半打开连接被期望是不同寻常的,恢复过程仅轻微涉及。

如果在A端连接不再存在,则用户在B端在该连接发送任何数据会导致B端的TCP接收到一个reset控制信息。该信息指示B端TCP连接发生了错误,且它被期望终止连接。

假设两个用户进程A和B相互通信,这时一个崩溃发生导致了A端TCP失忆。依赖于操作系统对A端TCP的支持,有可能存在一些错误恢复机制。当TCP重新启动,A可能从最开始点启动或者从一个恢复点启动。因此,A可能会尝试重新打开连接或者在他认为打开的连接上发送数据。在后一种情况中,它会从本地(A的)TCP收到“连接未打开”的错误信息。在尝试建立连接时,A端TCP会发送一个包含SYN的分片。这个例子在下图中展示。TCP A崩溃后,用户尝试重新打开连接。同时TCP B认为连接是打开的。

      TCP A                                           TCP B

  1.  (CRASH)                               (send 300,receive 100)

  2.  CLOSED                                           ESTABLISHED

  3.  SYN-SENT -->               --> (??)

  4.  (!!)     <--      <-- ESTABLISHED

  5.  SYN-SENT -->               --> (Abort!!)

  6.  SYN-SENT                                         CLOSED

  7.  SYN-SENT -->               -->

                     Half-Open Connection Discovery

                               Figure 10.


当SYN在线3到达的时候,TCP B,正处于同步状态,且到来的分片在窗口之外,以一个确认响应,该确认指示了他期望听倒的下一个系列号(ACK 100)。TCP A发现这个分片没有对他发送的分片作任何确认,处于未同步状态,由于它检测到了一个半打开的连接就发送了一个reset(RST)。TCP B在线5中断了连接。TCP A继续尝试建立连接,问题就变成基本的三次握手。

另外一种有趣的情况是当TCP A崩溃时,TCP尝试在它认为是一个同步的连接上发送数据。这种情况在下图中展示。在这种情况中,从B到达A(线2)的数据由于没有连接存在不被接收,所以TCP A发送了一个RST。RST是可接受的,所以TCP B处理了该RST,然后终止了连接。

       TCP A                                              TCP B

  1.  (CRASH)                                   (send 300,receive 100)

  2.  (??)    <-- <-- ESTABLISHED

  3.          -->                    --> (ABORT!!)

           Active Side Causes Half-Open Connection Discovery

                               Figure 11.
在下图中,我们发现TCP A和B都处于被动等待SYN连接。一个老的重复分片到达TCP B(线2),触发了B的动作。一个SYN-ACK被返回(线3),并且导致了TCP A产生了一个RST(线3的ACK是不能被接受的),TCP B接受了reset,且返回到被动监听状态。

      TCP A                                         TCP B

  1.  LISTEN                                        LISTEN

  2.       ...                 -->  SYN-RECEIVED

  3.  (??) <--    <--  SYN-RECEIVED

  4.       -->               -->  (return to LISTEN!)

  5.  LISTEN                                        LISTEN

       Old Duplicate SYN Initiates a Reset on two Passive Sockets

                               Figure 12.
各种各样的情况都有可能,所有的这些情况遵循RST产生和处理的规则。

Rest产生

作为一条基本规则,reset(RST)在一个分片到达且明显不是当前连接的分片的任何时候必须被发送。如果还不清楚,reset不能被发送。

有三组状态:

1.       如果连接不存在(关闭),那么reset被发送来响应任何到来分片(另外一个reset除外)。特别的,属于一个不存在的连接的SYN被这个方式拒绝。
如果到来分片有ACK字段,reset从该分片的ACK字段提取系列号,否则reset系列号取0,ACK字段设置成系列号和到来分片的分片长度的和。连接保留在关闭(CLOSED)状态。

2.       如果连接处于非同步状态(LISTEN,SYN-SENT,SYN_RECEIVED),到来分片对没有发送的东西进行确认(分片携带了不被接受的ACK),或者一个到来分片同连接要求的安全级别或者分隔没有严格匹配,reset被发送。
如果我们的SYN还没有被确认且到来分片的优先级别高于要求的优先级别,则双方都提高本地优先级别(如果用户和系统允许的话)或者发送一个reset;或者如果到来分片的优先级别低于要求的优先级别,则继续,就像优先级别严格匹配一样。(如果远端TCP不能提高优先级别来匹配我们的优先级别,在下一个它发送的分片中会被检测到,且连接将会被终止)。如果我们的SYN已经被确认(可能是在这个到来的分片中),到来分片的优先级别必须同本地优先级别严格匹配,如果没有匹配,一个reset必须被发送。
如果到来分片有一个ACK字段,reset从分片的ACK字段中提取系列号。否则,reset的系列号为0,ACK字段设置成到来分片系列号和分片长度的和。连接维持同一状态。

3.       如果连接处于同步状态(ESTABLISHED,FIN-WAIT-1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT),任何不被接受的分片(在系列号窗口之外或者不被接受的确认号码)必须仅发出一个包含当前发送队列号码和指示下一个期望被收到的系列号的确认的确认分片,且连接维持在相同的状态。
如果到来分片同连接要求的安全级别、分隔不一样,reset被发送,连接进入到CLOSED状态。Reset从到来分片的ACK字段提取系列号。

Reset处理

在除了SYN-SENT之外的所有状态中,所有的reset(RST)分片通过检查他们的SEQ字段被验证有效。如果一个reset的系列号在窗口内,则它是有效的。在SYN-SENT状态中(一个reset作为一个初始SYN的响应被收到),如果ACK字段确认了SYN,RST是可以接受的。

RST的接收者首先验证它,然后改变状态,如果接收者处于LISTEN状态,它可以忽略RST。如果接收者处于SYN-RECEIVED状态,且之前处于LISTEN状态,则接收者返回到LISTEN状态,否则接收者终止连接然后进入CLOSED状态。如果接收者处于其它的状态,它终止连接,告知用户,进入CLOSED状态。
阅读(3253) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~