概述

TCP提供一种面向连接的、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)的字节流服务。

如何保证高可靠:

  • 应用数据被分割成TCP认为最适合发送的数据块。
  • 当TCP发出一个段后,它启动一个定时器,等待目的端确认接收到这个报文段。如果不能及时收到一个确认时,将重新发送这个报文段。
  • 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送的,通常会延迟几分之一秒。
  • TCP将保持它首部和数据的校验和。
  • TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
  • TCP接收端必须丢弃重复的数据。
  • TCP提供流量控制。TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

报文格式

tcp报文格式

  • 源端口【16bit】和目的端口【16bit】。源端口号标识了发送主机的进程,目标端口号标识接受方主机的进程

  • 序号【32bit】:用来标识从 TCP源端向 TCP目的端发送的数据字节流,它表示在这个报文段中的 第一个数据字节的顺序号。如果将字节流看作在两个应用程序间的单向流动,则 TCP用顺序号对每个字节进行计数。序号是 32bit的无符号数,序号到达 2^32- 1后又从 0开始。当建立一个新的连接时, SYN标志变 1,顺序号字段包含由这个主机选择的该连接的初始顺序号 ISN( Initial Sequence Number)

  • 确认号【32bit】: 包含发送确认的一端所期望收到的下一个顺序号。因此,确认序号应当是上次已成功收到数据字节顺序号加 1。只有 ACK标志为 1时确认序号字段才有效。 TCP为应用层提供全双工服务,这意味数据能在两个方向上独立地进行传输。因此,连接的每一端必须保持每个方向上的传输数据顺序号。

  • 偏移【4bit】:实际指的是TCP首部的长度,它用来表明TCP首部中32 bit字的数目,通过它可以知道一个TCP包它的用户数据是从哪里开始的。这个字段占4bit,如4bit的值是0101,则说明TCP首部长度是5 * 4 = 20字节。 所以TCP的首部长度最大为15 * 4 = 60字节。然而没有可选字段,正常长度为20字节。

  • 保留【6bit】:目前没有使用,它的值都为0

  • 标志【6bit】,即控制位,在TCP首部中有6个标志比特。他们中的多个可同时被置为1。

    • URG:紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送,相当于高优先级的数据,而不用按原来的排队顺序来传送。URG置1时,发送应用进程就告诉发送方的tcp有紧急数据要传送,于是发送发TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。
    • ACK:确认序号有效。当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1
    • PSH 推送:指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满
    • RST 复位:一般表示断开一个连接
    • SYN 同步:在连接建立时同步序号。 当SYN=1而ACK=0时,表明连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1且ACK=1。
    • FIN 终止:释放一个连接,当FIN=1时,表明此报文段的发送方数据已发送完毕,并要求释放连接。
  • window 窗口【16bit】:发送报文段一方的接收窗口。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。窗口作为接收方让发送方设置其发送窗口的依据。

  • 校验和 checksum 【16bit】:校验和覆盖了整个的TCP报文段:TCP首部和TCP数据。这是一个强制性的字段,一定是由发送端计算和存储,并由收端进行验证。

  • 紧急指针【16bit】:仅在URG=1时才有意义。指出本报文段中紧急数据的字节数。 即使窗口为0时,也可发送紧急数据。

  • 选项:长度可变,最长可达40个字节。
    选项的基本结构:
    tcp选项的基本结构
    常见的tcp选项有7个:
    常见的tcp选项

    • kind=0是选项表结束选项。
    • kind=1是空操作(nop)选项,没有特殊含义,一般用于将TCP选项的总长度填充为4字节的整数倍。
    • kind=2是最大报文段长度选项。TCP连接初始化时,通信双方使用该选项来协商最大报文段长度(Max Segement Size,MSS)。TCP模块通常将MSS设置为(MTU-40)字节(减掉的这40字节包括20字节的TCP头部和20字节的IP头部)。这样携带TCP报文段的IP数据报的长度就不会超过MTU(假设TCP头部和IP头部都不包含选项字段,并且这也是一般情况),从而避免本机发生IP分片。对以太网而言,MSS值是1460(1500-40)字节。
    • kind=3是窗口扩大因子选项。TCP连接初始化时,通信双方使用该选项来协商接收通告窗口的扩大因子。在TCP的头部中,接收通告窗口大小时用16位表示的,故最大为65535字节,但实际上TCP模块允许的接收通告窗口大小远不止这个数(为了提高TCP通信的吞吐量)。窗口扩大因子解决了这个问题。假设TCP头部中的接收通告窗口大小是N乘2的M次方,或者说N左移M位。注意,M的取值范围是0~14。我们可以通过修改/proc/sys/net/ipv4/tcp_window_scaling内核变量来启用或关闭窗口扩大因子选项。
    • kind=5是SACK实际工作的选项。该选项的参数告诉发送方本端已经收到并缓存的不连续的数据块,从而让发送端可以据此检查并重发丢失的数据块。每个块边沿(edge of block)参数包含一个4字节的序号。其中块左边沿表示不连续块的第一个数据的序号,而块右边沿则表示不连续块的最后一个数据的序号的下一个序号。这样一对参数(块左边沿和块右边沿)之间的数据是没有收到的。因为一个块信息占用8字节,所以TCP头部选项中实际上最多可以包含4个这样的不连续数据块(考虑选项类型和长度占用的2字节)。
    • kind=8是时间戳选项。该选项提供了较为准确的计算通信双方之间的回路时间(Round Trip Time,RTT)的方法,从而为TCP流量控制提供重要信息。我们可以通过修改/proc/sys/net/ipv4/tcp_timestamps内核变量来启用或关闭时间戳选项。

建立连接的三次握手过程

tcpdump 抓取包如下:
建立连接的过程
分析:

  1. 请求端发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN,在这为1632134727)。这个SYN段为报文段1。

    a82e 源端口号 43054
    0050 目标端口号 80
    6148 6647 sys序号 1632134727
    0000 0000 ack确认号
    a0 首部长度 10*4 = 40字节
    02 表示控制位 SYN为1
    7210 表示窗口大小 29200
    4313 表示校验码
    0000 表示紧急指针
    0204 05b4 表示kind=2 len=4 mss为1460
    0402 表示开启sackok
    080a 0007 2597 0000 0000 表示kind=8 len=10 时间戳值为 468375 时间戳回显应答值为0
    0103 0307 表示 nop, kind=3 len=3 移位值为7 也就是窗口扩大因子为7

  2. 服务器发回包含服务器初始序号的SYN报文段(报文段2)作为应答,同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。

    0050 源端口号 80
    a82e 目标端口 43054
    c2df 6fa5 syn序号
    6148 6648 ack确认号为 1632134728
    a012 首部长度为40字节,控制位SYN和ACK置1
    2000 窗口大小 8192
    4586 检验和
    0000 紧急指针
    0204 05ac 表示 kind=2 len=4 mss为1452
    0402 表示开启sackok
    01 表示 nop
    0103 0305 表示nop,kind=3 len=3 移位值为5 也就是窗口扩大因子为5

  3. 客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认

    a82e 0050 源端口 目标端口
    6148 6648 序号
    c2df 6fa6 ack确认号
    5010 首部长度为20 控制位ACK置1
    00e5 窗口大小 229
    42ff 检验和
    0000 紧急指针

用如下图表示:
三次握手过程

释放连接过程

  • 建立一个连接需要三次握手,而终止一个连接需要4次握手,这是由TCP的半关闭造成的。既然一个TCP连接是全双工,因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向连接,当一端收到一个FIN,它必须通知应用层另一端已经终止了那个方向的数据传送。发送FIN通常是应用层进行关闭的结果。
  • 发送一个FIN只意味着在这一方向上没有数据流动。一个TCP连接在收到一个FIN后仍能发送数据。

tcpdump 抓取包如下:
释放连接过程
分析:

  1. 主动关闭的一方发送FIN报文段 一个FIN占用一个序号

    0050 88f6 源端口 目标端口
    dffb 4621 9feb 77c0 序号 确认号
    5011 首部长度20字节,控制位ACK和FIN置1
    0394 窗口大小
    a24c 校验和
    0000 紧急指针

  2. 被动关闭的一方发送FIN报文段

    88f6 0050 源端口 目标端口
    9feb 77c0 dffb 4622 序号 确认号
    5011 首部长度20字节,控制位ACK和FIN置1
    00e5 窗口大小
    42fe 校验和
    0000 紧急指针

  3. 主动关闭一方发送ack应答

    0050 88f6 源端口 目标端口
    dffb 4622 9feb 77c1 序号 确认号
    5010 首部长度20字节,控制位ACK置1
    0394 窗口大小
    a24b 校验和
    0000 紧急指针

用如下图表示:
四次挥手过程

tcp状态转换

tcp状态转换图

访问没有使用的端口

访问不存在的端口
当访问一个没有使用的端口时,产生一个复位报文段。注意复位报文段中序号被置为0,确认序号被置为进入的ISN加1

#

文档更新时间: 2021-02-25 17:05   作者:周国强