备注:这是一篇笔记,主要是为了方便平时对 TCP/IP 协议细节的查阅,仅供参考

TCP/IP 协议报头一览图

图片来源于这篇文章

上图中 TCP 的标记字段目前为 8 bits,多了两位(CWRECE)。

IPv4 Header

  • 版本(Version)

    4 bits,标识了数据包的 IP 版本号。其中:

    • 0100:IPv4
    • 0110:IPv6

    其他版本均可认为是历史产物;

  • 报头长度(IP Header Length)

    4 bits,表示 32 位长的 IP 报头长度。比如当 IHL 为 5 时,则 IP 数据报头长度为 5*32=160 bits,即 160/8=20 bytes。一般情况下,IHL 为 5,即 IP 报头最小为 20 个字节,最大为 (2^4-1)*32=480 bits,即 60 个 bytes

  • 服务类型(TOS)

    8 bits。最早设计被划分为两个子字段:优先权和 TOS,如下图所示:

    优先权用来设置数据包的优先级,TOS 允许按照吞吐量、时延、可靠性和开销方式来选择传输服务。

    由于 TOS 从来没被广泛使用过,因此最终这个 8 位长的字段被分成两个部分并被一组 RFC 重新定义:前 6 bits 称为区分服务字段(DiffServ),后 2 bits 是显式拥塞通知(Explicit Congestion Notification,ECN)字段或指示位,如下图所示:

    区分服务架构为 IP 数据包提供比之前 TOS 的设计更为灵活的处理方式。在 DiffServ 下,我们能够在一台路由器上定义服务分类,将数据包归类到这些分类中去。路由器可以根据它们的分类使用不同的优先级对数据包进行排序和转发,每一个排序和转发的处理称为一个 Per-Hop Behavior(PHB)。

    在由 6 bits 构成的区分代码点(DiffServ Code Point,DSCP)中,我们可以使用任意数值或根据区分服务体系结构中预定义的服务类别,最多可定义 64 个不同的服务类别,并整理到 PHB 中。

    而某些路由器支持 ECN 时,这些位可用于拥塞信号(ECN = 11);

  • 总长度(Total Length)

    16 bits,IP 数据包(包括报头)的总长度(以 bytes 为单位),即 IP 数据包最大可以是 65535 bytes;

  • 标识符(Identifier)

    16 bits,通常与标记字段和分片偏移字段一起用于数据包分片。如果数据包原始长度超过数据包所要经过的数据链路的最大传输单元(MTU),那么必须将数据包分片为更小的数据包。

    例如:一个大小为 5000 字节的数据包在穿过网络时,如果遇到一条 MTU 为 1500 字节的数据链路,则路由器需要在数据成帧之前将数据包分片为多个数据包,其中每个数据包长度不同超过 1500 字节,然后路由器在每片数据包的标识字段上打上相同的标记,以便接收设备可以识别属于一个数据包的分片(被分片的数据包不会在数据链路的另一端被重组,而是一直保持分片状态,直至到达最终目的地时才会被重组);

  • 标记字段(Flag)

    3 bits,其中: - 第 1 位没有使用; - 第 2 位是不分片(DF)位,当 DF 位被设置为 1 时,表示路由器不能对数据包进行分片处理。如果数据包不能分片而无法转发,那么路由器将丢弃该数据包并向源站发送错误消息,这一功能可用于在网络测试 MTU 值; - 第 3 位表示还有更多分片(MF)位。当路由器对数据包进行分片时,除了最后一个分片的 MF 位设置位 0 之外,其他所有分片的 MF 均设置为 1,以便接收者直到收到 MF 位为 0 的分片为止;

  • 分片偏移(Fragment Offset)

    13 bits,以 8 个八元组为单位(为了使 13 位长的分片偏移字段可以表示的最大数据包长度为 65535 字节),用于指明分片起始点相对于报头起始点的偏移量;

  • 生存时间(TTL)

    8 bits,在最初协议设计时,TTL 被设置为某个特定值(以秒为单位),当数据包逐个沿着路由器被传输时,每台路由器都会降低 TTL 的值。当 TTL 为 0 时,路由器将丢弃该数据包并向源点发送错误信息,这种方法可以防止数据包在网络上无休止地被传输。后发现以时间为单位实施起来非常困难,将其改成跳数。常见为 15 和 32,建议默认值为 64;

  • 协议

    8 bits,给出了主机到主机层(传输层)的协议,常见的有:

    • 1:ICMP(Internet 消息控制协议)
    • 2:IGMP(Internet 组管理协议)
    • 4:IPIP(被 IP 协议封装的 IP 协议)
    • 6:TCP
    • 17:UDP
    • 18:GRE(通用路由选择封装)
    • 89:OSPF
  • 报头校验和(Header Checksum)

    16 bits,仅仅计算 IPv4 头部,IP 协议不检查数据的正确性。由于每台路由器都会降低数据包的 TTL,所以每台路由器都必须重新计算校验和;

  • 源地址和目的地址

    均为 32 bits,分别表示发送者数据包源点和目的地的 IP 地址;

  • 可选项(Options)

    如果选项存在,它在 IPv4 分组中紧跟在基本 IPv4 头部之后。选项由一个 8 bits 的类型字段标识,该字段被细化为 3 个字字段:

    • 复制:1 bit,表示如果相关数据包被分片,该选项是否被复制到分片中;

    • 类别:2 bits,表示选项的类别。除了 “时间戳” 和 “跟踪” 使用类别 2(调试和测量)位,其余选项使用类别 0(控制),类别 1 和 3 保留;

    • 编号:5 bits,表示不同的选项,可参考下图:

    选项 0 和 1 的长度为 1 个 byte,多数选项的长度可变。

    目前,多数标准化选项在 Internet 中极少被使用过,所以实际用处并不大。

  • 填充(Padding)

    该字段通过在可选字段后面添加 0 来补足 32 位,这样保证报头长度是 32 位的倍数

TCP Header

  • 源端口号和目的端口号

    均为 16 bits。这两个值与 IP 头部的源和目的 IP 地址一起,唯一标识了每个 TCP 连接(socket)

  • 序列号(Sequence Number)和确认号(Acknowledgment Number)

    均为 32 bits。序号用来标识从 TCP 发端向 TCP 收端发送的数据字节流,它表示在这个报文段中的第一个数据字节。这是一个无符号数,序号到达 2^32-1 后又从 0 开始。 初始序列号(Initial Sequence Number,ISN)一般是一个随机数;

    既然每个传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号,因此,确认序号是上次已成功接收的序列号加上接收长度再加 1。如果这次发送序列号是 1089,发送 512 bytes 数据给对端,当对端成功接收到该数据时,将会发送一个确认包,其 ACK Number 为 1089+512+1=1602,这也是下一个将要发送数据包的序列号。这个字段只有在 ACK 位字段被启用的情况下才有效。发送一个 ACK 与发送一个 TCP 报文段的开销是一样的。

    消耗一个序列号也就意味着必须使用重传来进行可靠传输,因此,SYN,FIN 和应用程序字节都是可靠传输,而不消耗序列号的 ACK 则不是

    注意: TCP 是面向字节流的协议,会对每一个字节进行编号。如果收到确认号 = N,则表示序号 N-1 为止的数据都已正确收到

  • 报头长度

    4 bits,以 32 位字位单位。当 TCP 带选项字段时,报头长度不固定,所以该字段是必须的。TCP 的报头最大为 (2^4-1)*32=480 bits,即 60 bytes。当 TCP 不带选项时(一般情况下),大小为 20 bytes,这点与 IP 报头一样

    报头长度后的 4 bits 为保留位;

  • 标记(Flag)

    8 bits,每一个 bit 都标记着不同含义,主要用于流和连接控制。如:

    • CWR(Congestion Window Reduced):拥塞窗口减少(发送方降低它的发送速率);

    • ECE(ECN-Echo):ECN 回显(发送方接收到了一个更早的拥塞通告);

    • URG:紧急(紧急指针字段有效,很少被使用);

    • ACK:确认(ACK Number 字段有效,连接建立以后一般都是启用状态);

    • PSH:推送(接收方应尽快给应用程序传送这个数据,该字段没被可靠地实现或用到);

    • RST:重置连接(连接取消,经常时因为错误);

    • SYN:用于初始化一个连接的同步序列号;

    • FIN:该报文段的发送方已经结束向对方发送数据;

  • 窗口大小

    16 bits,字节数,用于流控。窗口指的是发送本报文段的一方的接收窗口。窗口告诉对方:从本报文段首部的确认号算起,接收方目前允许对方发送的数据量。

    比如:确认号为 701,窗口字段是 1000,这就表明:从 701 号算起,发送方还可接收 1000 个字节,即 701~1700 的接收缓存空间。

    窗口字段明确指出了现在允许对方发送的数据量。窗口值是经常在动态变化的

  • 校验和

    16 bits,包括报头和被封装的数据;

  • 紧急指针(Urgent Pointer)

    只有在 URG 位字段被设置时才有效;

  • 选项和填充

    最常见的选项字段是 MSS(最大段长度,Maximum Segment Size)选项,一般在连接时发送的第一个报文段(SYN)上指定这个选项。MSS 是每一个 TCP 报文段中的数据字段的最大长度,数据字段加上 TCP 首部才等于整个 TCP 报文段,所以:MSS = TCP 报文段长度 - TCP 首部长度

    为什么要规定 MSS ?MSS 与窗口值无关,主要是为充分利用网络使用率:数据字段太小,则有可能 TCP 头部和下几层协议所附带的信息会远超数据字段;数据段太大,则有可能会导致 IP 分片,顾最佳 MSS 总是很难确定的。

参考资料