TCP被作为一种运行在分组交换网络(以及它们的互联系统)上的高可靠的主机到主机协议。TCP是面向连接的、端到端的通用协议,却对下层协议的假设甚少(可以是多网络环境,只要求一个不可靠的报文服务),一般用于互联网上不同主机的进程间通信。 现行协议版本被IETF标准化为RFC-793

虽然TCP主要运行在互联网的IP协议层之上,但原则上,TCP能够在多种通信系统上进行操作,从硬连线连接到分组交换或电路交换系统。

概述

互联网系统元素

Internet环境由连接在通过网关互联的网络上的主机组成。为了在不同主机的进程间通信,网络上运行着多层的协议。

分组 是主机以及它所在网络上一次交换的数据。 主机 是连在网络上的计算机,是分组的源和目标。 进程 是主机上的活跃元素。

一个进程可能需要独立的多个连接,于是每个进程可以有多个端口来和其他进程通信。

操作模型

进程通过调用TCP(以数据缓存作为参数)进行数据传输。TCP将数据打包为片段(segment),调用互联网模块传输给目标TCP。接收方TCP将每个片段放在接收用户的缓存中,然后提示用户。

TCP在片段中包括控制信息,被用来确保传输数据的顺序。

每个TCP模块关联着一个提供本地网络接口的IP模块,该模块将TCP片段打包成IP数据包,并将其路由到目标IP模块或中间网关。为了在本地网络中传输该数据报,它又被嵌入到本地网络分组中。 分组交换继续做打包、分段等其他操作来递送本地网络分组给目标IP模块。

在网络间的网关上,打开本地网络分组,得到IP数据报。然后决定接下来应该发送该数据报到那个网络。此后,该数据报被打包进适合下一个本地网络的本地网络分组,路由给下一网关或最终目标。

网关可以根据需要将IP数据报切分成较小的数据报片段。切分后的片段也可能被再次切分。根据IP数据报分片的格式的设计,目标IP模块可以将分片组装为IP数据报。

目标IP模块将数据报(如果需要,先进行组装)中的数据拿出来,传送给目标TCP模块。

简单的模型中仍有很多的细节,比如服务类型。它为网关选择下一个网络的服务参数提供了信息。服务类型包括数据报的优先级,或者安全信息。这些允许主机和网关根据安全考虑,进行多安全层次的操作来分离数据报。

连接

TCP连接用一对socket来标识,且TCP连接可以向两个方向传送数据,即TCP是全双工的。同时每个端口可以任意绑定一个进程,进程只能对属于自己的端口进行初始化。

每个数据流都需要维护一些状态信息。这些信息(包括socket、序列号、窗口大小)组成一个连接。一个连接用一组socket标识。

通信之前,双方应该建立一个连接。结束通信后连接被终止或关闭,释放的资源可供他用。

为了在不可靠的Internet上建立连接和避免错误的连接初始化,TCP采用了握手机制和基于时钟的序列号。

接口

TCP应作为操作系统的一个模块。其用户接口包括OPEN,CLOSE,SEND,RECEIVE,STATUS。这些调用就像是文件调用一样:打开、读、关闭。TCP通过IP来间接调用本地网络接口,TCP接口提供了发送(或接收)数据报给任何互联网中TCP地址的调用。

优先级与安全性

使用TCP的用户可能会指定优先级和安全性。当这些特性未被使用时,应提供默认值。

操作

TCP允许的操作包括以下几个方面:

基本数据传输

TCP能够在两个方向上传输连续的字节流,通常会把一些字节打包成片段,然后交给互联网系统进行传输。

通常TCP可以根据自己的方便,进行阻塞和转发。因此需要提供PUSH操作,以免用户需要立即发送。该操作会导致TCP立即转发数据,但这个过程对接收方应是不可见的。

可靠性

TCP能够从传输错误中恢复,除非互联网完全断开。传输错误包括:损坏、丢失、重复、乱序。

为了实现这个目的,每个传输的字节都被标记一个序列号(SEQ),同时接收方应提供确认号(ACK)。如果确认号超时,则重发数据。在接受端,序列号用来重新排列乱序或重复的片段。数据损坏用一个校验值来处理,在接收端抛弃损坏的片段。

流控制

TCP提供了一种手段来管理发送者发送的数据量。接收者发送一个“窗口”(接下来期望接受的字节范围)给发送者,发送者在接收到进一步允许前只能发送这些字节。

多路复用

为了允许同一主机的不同进程同时使用TCP设施,TCP提供了一组端口,加上互联网通信层地址(IP),组成一个socket。一对socket唯一地标识了一个TCP连接。 而一个进程可以绑定到端口来监听网络。为了方便,将常用进程绑定到公开的确定端口。这样就可以通过公共地址来访问服务了。

对于其他非公开确定的端口,建立连接涉及到更多的动态机制。

TCP头

在传送的片段中,TCP头的位置紧接着IP头,其中提供了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                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

字段说明:

  1. Source/Destination Port:源与目标端口。
  2. Sequence Number:该片段中第一个数据字节的序列号。如果SYN是1,则该序列号成为初始序列号(ISN),第一个数据字节为ISN+1
  3. Acknowledgment Number:如果ACK是1,该字段包含期望收到的下一个序列号。
  4. Data Offset:TCP头的长度,也就是数据的起始位置。单位为32位字。
  5. Reserved:保留字段,必须为0。
  6. Conrol Bits
    • URGUrgent Pointer字段起作用。
    • ACKAcknowledgment字段起作用。
    • PSHPUSH功能。
    • RST:重置连接。
    • SYN:同步序列号。
    • FIN:别再发送了。
  7. Window:期望接收的字节长度,从Acknowledgment开始。
  8. Checksum:头和数据中所有16位字的反码和的反码。如果是奇数字节,最后字节后补零。计算该字段时,该字段值为0。该校验和还包含了伪头部,它包含IP地址,用来防止路由错误。
  9. Urgent Pointer:当前紧急数据的开始位置,从序列号算起。
  10. Options:该字段位于TCP头的末尾,可以有多个整字节。可以包括选项类型、选项长度、选项数据。
  11. Padding:值为0的补白,确保TCP头长度为32位的整数倍。

TCP状态

一个TCP连接在整个生命周期内可能处在不同的状态,包括:

  1. LISTEN:等待任何远程TCP的连接请求。
  2. SYN-SENT:发送连接请求后,等待匹配连接请求。
  3. SYN-RECEIVED:收到并发送一个连接请求后,等待连接请求确认。
  4. ESTABLISHED:一个打开的连接,收到的数据可以递交给用户,正常的数据传输状态。
  5. FIN-WAIT-1:等待远程TCP的终止请求,或等待终止请求的确认。
  6. FIN-WAIT-2:等待远程TCP的终止请求。
  7. CLOSE-WAIT:等待本地用户的连接终止请求。
  8. CLOSING:等待远程TCP的终止请求确认。
  9. LAST-ACK:等待远程TCP终止请求的确认,之前发送的终止请求包含终止请求的确认。
  10. TIME-WAIT:等待足够的时间,确保远程TCP收到了终止请求的确认。
  11. CLOSED:没有任何连接状态。

建立连接

使用OPEN调用来声明一个连接,同时提供本地端口、远程socket参数、以及被动等待还是主动连接。此时TCP会提供一个名称(关联着传输控制块,TCB,来存储该连接的变量的数据结构)用于后续调用。两个进程如果同时发起主动连接,它们也会正确地建立连接。这种灵活性在分布式系统中至关重要。

本地被动连接可以指定远程socket,也可以不指定。后者将会接受所有的远程socket。

建立连接采用三步握手过程,一般是一方初始化请求,另一方响应该请求。以下是一个简单的建立连接过程:

    TCP A                                                TCP B
1.  CLOSED                                               LISTEN

2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED

3.  ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED

4.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK>       --> ESTABLISHED

5.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED

注意第5行,此时发送了一些数据,而SEQ值没有变,因为ACK报文不占用序列号空间(不同于数据和SYN)。否则我们将需要确认ACK

对于同时发起连接,将会稍微复杂一些:

    TCP A                                            TCP B

1.  CLOSED                                           CLOSED

2.  SYN-SENT     --> <SEQ=100><CTL=SYN>              ...

3.  SYN-RECEIVED <-- <SEQ=300><CTL=SYN>              <-- SYN-SENT

4.               ... <SEQ=100><CTL=SYN>              --> SYN-RECEIVED

5.  SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...

6.  ESTABLISHED  <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED

7.               ... <SEQ=101><ACK=301><CTL=ACK>     --> ESTABLISHED

三路握手过程可以从旧的重复SYN中恢复,要用到RST字段:

    TCP A                                                TCP B

1.  CLOSED                                               LISTEN

2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               ...

3.  (duplicate) ... <SEQ=90><CTL=SYN>               --> SYN-RECEIVED

4.  SYN-SENT    <-- <SEQ=300><ACK=91><CTL=SYN,ACK>  <-- SYN-RECEIVED

5.  SYN-SENT    --> <SEQ=91><CTL=RST>               --> LISTEN


6.              ... <SEQ=100><CTL=SYN>               --> SYN-RECEIVED

7.  SYN-SENT    <-- <SEQ=400><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED

8.  ESTABLISHED --> <SEQ=101><ACK=401><CTL=ACK>      --> ESTABLISHED

注意,第3行是旧的重复SYN,接收方在不知情的情况下仍然确认了该SYN。此时,发送方应重置该SYN(地5行)。然后继续新的连接。

另外一种情况是一方因故关闭,造成半开的连接。TCP的策略是发现这种情况并关闭该连接后重新由关闭方发起连接。

    TCP A                                           TCP B

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

2.  CLOSED                                           ESTABLISHED

3.  SYN-SENT --> <SEQ=400><CTL=SYN>              --> (??)

4.  (!!)     <-- <SEQ=300><ACK=100><CTL=ACK>     <-- ESTABLISHED

5.  SYN-SENT --> <SEQ=100><CTL=RST>              --> (Abort!!)

6.  SYN-SENT                                         CLOSED

7.  SYN-SENT --> <SEQ=400><CTL=SYN>              -->

注意,接收到RST后首先进行验证(RSTSEQ必须在窗口内),然后进行重置。

关闭连接

TCP是全双工的,CLOSE操作却是单工的方式:CLOSE之后不再发送数据,但仍然可以继续接收数据直到远程TCP关闭。即CLOSE意味着:我没有要发送的数据了。

对于一方首先关闭连接的情况:

    TCP A                                                TCP B

1.  ESTABLISHED                                          ESTABLISHED

2.  (Close)
    FIN-WAIT-1  --> <SEQ=100><ACK=300><CTL=FIN,ACK>  --> CLOSE-WAIT

3.  FIN-WAIT-2  <-- <SEQ=300><ACK=101><CTL=ACK>      <-- CLOSE-WAIT

4.                                                       (Close)
    TIME-WAIT   <-- <SEQ=300><ACK=101><CTL=FIN,ACK>  <-- LAST-ACK

5.  TIME-WAIT   --> <SEQ=101><ACK=301><CTL=ACK>      --> CLOSED

6.  (2 MSL)
    CLOSED

对于双方同时关闭连接的情况:

    TCP A                                                TCP B

1.  ESTABLISHED                                          ESTABLISHED

2.  (Close)                                              (Close)
    FIN-WAIT-1  --> <SEQ=100><ACK=300><CTL=FIN,ACK>  ... FIN-WAIT-1
                <-- <SEQ=300><ACK=100><CTL=FIN,ACK>  <--
                ... <SEQ=100><ACK=300><CTL=FIN,ACK>  -->

3.  CLOSING     --> <SEQ=101><ACK=301><CTL=ACK>      ... CLOSING
                <-- <SEQ=301><ACK=101><CTL=ACK>      <--
                ... <SEQ=101><ACK=301><CTL=ACK>      -->

4.  TIME-WAIT                                            TIME-WAIT
    (2 MSL)                                              (2 MSL)
    CLOSED                                               CLOSED

MSL: Maximum Segment Lifetime, the time a TCP segment can exist in the internetwork system. Arbitrarily defined to be 2 minutes.

参考:RFC-793

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2014/09/27/tcp.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。