1. TCP的服务

TCP处于传输层,提供了一种面向连接的可靠的字节流(byte stream)服务。

第一个特性面向连接是指两个TCP应用(通常是一个客户端和一个服务端)在彼此交换数据之前必须先建立一条连接。在一个TCP连接中,仅有两方进行彼此通信。

第二个特性可靠性是通过下列方式来提供的:

  • 应用数据被分割成TCP认为最适合发送的数据库(这和UDP完全不同,在UDP中,应用程序产生的数据报长度保持不变)。由TCP传递给IP的信息单位称为报文段或者段(segment)。
  • 当TCP发出一个段以后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
  • 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常是推迟几分之一秒。
  • TCP将保持它首部和数据的校验和。这是一个端到端的校验和,目的是检测数据在传输过程中的任何变化。如果收到段的校验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
  • 既然TCP报文段作为IP数据报来发送,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
  • 既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。
  • TCP还能提供流量控制。TCP连接的每一个都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

第三个特性字节流指两个应用程序通过TCP连接交换8位(bit)构成的字节流。TCP不在字节流中插入任何记录标示符。另外,TCP对字节流的内容不做任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCII字符、EBCDIC字符或者其他类型的字符。对字节流的解释由TCP连接双方的应用层解释。

2. TCP的首部

TCP数据被封装在一个IP数据报中,如图1所示:

tcp_head

如图,TCP报文段由TCP首部和TCP报文段的数据部分(可为空)组成;而IP数据报则由IP首部和TCP报文段 (作为IP数据报的数据部分)组成。

如果不计任何任选字段,TCP首部通常由20个字节(byte)组成:

  • 1~4字节(4 byte = 32 bit,0~31 bit)为源端口号(16bit)和目的端口号(16bit)。用于寻找发端和收端的应用进程。这两个值加上IP首部中的源端IP地址和目的端IP地址唯一确定一个TCP连接。在RFC793规范中,一个IP地址和一个端口号称为一个socket,后来也用来表示网络编程中的编程接口,即我们熟悉的套接字。一个四元组(socket pair){ 客户端IP地址,客户端端口,服务器IP地址,服务器端口号 }可唯一确定一个互联网络中每个TCP连接的双方。
  • 5~8字节为序号(32bit)。序号用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的第一个数据字节。如果将字节流看做在两个应用程序间的单向流动,则TCP用序号对每个字节进行计数。序号是32bit的无符号数,序号到达$2^{32}-1$后又从0开始。当建立一个新的连接时,SYN标志变为1.序号字段包含由这个主机选择的该连接的初始序号ISN(Initial Sequence Number)。该主机要发送数据的第一个字节序号为这个ISN加1,以为SYN标志消耗了一个序号。
  • 9~12字节为确认号。既然每个传输的字节都要被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当是上次已成功收到数据字节序号加1.只有ACK标志为1时确认序号字段才有效。发送ACK无需任何代价,因为32 bit的确认号字段和ACK标志一样,总是TCP首部的一部分。因此,我们看到一旦一个连接建立起来,这个字段总是被设置,ACK标志也总是被设置为1.TCP为应用层提供全双工服务。这意味着数据能在两个方向上独立的进行传输。因此,连接的每一端必须保持自己方向上的传输数据序号。

    TCP可以表述为一个没有选择确认或否认的滑动窗口协议(滑动窗口协议用于数据传输)。我们说TCP缺少选择确认是因为TCP首部的确认序号表示发方(发送确认序号的一方)已成功收到字节,但还不包含确认序号所指的字节。当前还无法对数据流中选定的部分进行确认。例如,如果1~1024字节已经成功收到,下一个报文段中包含序号为从2049~3027的字节,那么收端并不能确认这个新的报文段。它能做的就是发回一个确认号为1025的ACK。它也无法对一个报文段进行否认。例如,如果收到包含1025~2048字节的报文段,但它的检验和错,TCP接收端所能做的就是发回一个确认序号为1025的ACK。
  • 13~14字节由4 bit的首部长度、6 bit的保留字段、6 bit的标志位组成。(1)首部长度:首部长度给出首部中32 bit字的数目。需要这个值是因为任选字段的长度是可变的。这个字段为4 bit,所以TCP最大的首部长度为60字节($(2^4-1)*32 bit = 60 byte$)。然而,一般都没有任选字段,所以TCP正常的首部长度为20字节。(2)6个标志位。这6个标志位中的多个可以同时被设置为1,它们的具体作用后面会陆续介绍,这里只简单说明一下:

    URG        紧急指针(urgent pointer)有效
    ACK        确认序号有效
    PSH        接收方应该尽快将这个报文段交给应用层
    RST       重建连接
    SYN        同步序号用来发起一个连接
    FIN        发端完成发送任务
  • 15~16字节为窗口大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16 bit字段,因为窗口大小最大为65535字节.
  • 17~18字节为检验和。检验和覆盖了整个TCP报文段:TCP首部和TCP数据。这是一个强制性字段,一定由发端计算和存储,并由收端进行验证。
  • 19~20字节为紧急指针。只有当URG标志置1时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式使发送端向另一端发送紧急数据的一种方式。

至此,常见的20字节长度的TCP首部就介绍完了。

  • 21~n字节(n ≤ 60)为首部可选字段。最常见的可选字段是最长报文大小(MSS,Maximum Segment Size)。每个连接通常都在通信的第一个报文段(为建立连接而设置SYN标志的那个段)中指明这个选项。他指明本端所能接收的最大长度的报文段。

最后附一张图(图片来源:https://nmap.org/book/tcpip-ref.html

MJB-TCP-Header-800x564.png