计算机网络 之 TCP协议报文结构

时间:2021-10-26 14:33:30

前言:上学期实训课,由于要做一个网络通信的应用,期间遇到各种问题,让我深感计算机网络知识的薄弱。于是上网查找大量的资料,期间偶然发现了roc大神的博客,很喜欢他简明易懂的博文风格。本文受roc的《计算机网络协议包头赏析-TCP》的启发,希望根据自己所学以及IETF的相关文档,在原有基础上,进行相应知识的扩充,特别地将针对大部分字段的用途进行分析。

 

(1)TCP报文格式图示:

计算机网络 之 TCP协议报文结构

 

  TCP报文段也分为首部和数据两部分,首部默认情况下一般是20字节长度,但在一些需求情况下,会使用“可选字段”,这时,首部长度会有所增加,但最长不超过60字节。

 

(2)固定头部的各字段的功能解说:

【源端口】- 16bit

  来源处的端口号;端口号有65536个,即2^16。我也写了一篇关于端口号的范围的分类的 《计算机网络 之 TCP和UDP的端口解析》,供大家参考。

【目的端口】- 16bit

  目的处的端口号;

【序号】- 32bit

  TCP在对数据进行分段的时候,会给每一个TCP报文段添加一个序号,序号字段的值其实是该文段所发送的数据的第一个字节的序号。这么做的原因是,TCP是面向连接的可靠服务,这个序号可以保证数据在传输过程中保持有序性,接受端可以通过这个序号确认收到的数据的完整性和先后顺序;

【确认号】- 32bit

  确认号,是期望收到对方的下一个报文段的数据的第一个字节的序号;(后续将会提供一片关于如何使用序号和确认号保证数据的完整性和有序性的文章供大家参考。)

【数据偏移】- 4bit

  其实它本质上就是“首部长度”,因为“数据偏移”是指TCP报文段的数据部分的起始处距离TCP报文段的起始处的距离。(仍然很拗口,但相信你能明白)。

  数据偏移总共占4bit,因此最大能表示的数值为15。但TCP的报文头部至少为20字节。因此数据偏移的单位是“4字节”,此处的设计和IP数据报的设计是完全相同的,所以说TCP报文段首部的长度最长为15×4=60字节,且首部长度必须为4字节的整数倍。

【保留字段】- 6bit

  IETF文档指出,这6bit在标准中是保留字段,留待以后使用,必须为0。我猜测,有两个目的,第一个是预留除URG/ACK/PSH/RST/SYN/FIN/之外的冗余功能位;第二个是为了对齐字节位。

【控制位】- 6bit

  又称为TCP flag,该字段从左到右分为以下六个字段,指明包的类型。同时用于控制TCP的状态机,同时ACK和SYN与三次握手协议有关,FIN与四次挥手协议有关。

  ① 紧急字段URG - 1bit

    当URG=1时,此字段告诉系统此报文段中有紧急数据,应尽快传送。

  ② 确认字段ACK - 1bit

    当ACK=1时,表示确认,且确认号有效;当ACK=0时,确认号字段无效。

  ③ 推送字段PSH - 1bit

    当PSH=1时,则报文段会被尽快地交付给目的方,不会对这样的报文段使用缓存策略。关于URG和PSH,有一篇博文的扩展:《TCP标志中的URG和PSH位》

  ④ 复位字段RST - 1bit

    当RST为1时,表明TCP连接中出现了严重的差错,必须释放连接,然后再重新建立连接。

  ⑤ 同步字段SYN - 1bit

    当SYN=1时,表示发起一个连接请求。

  ⑥ 终止字段FIN - 1bit

    用来释放连接。当FIN=1时,表明此报文段的发送端的数据已发送完成,并要求释放连接。

【窗口字段】- 16bit

  此字段用来控制对方发送的数据量,单位为字节。

  一般TCP连接的其中一端会根据自身的缓存空间大小来确定自己的接收窗口大小,然后告知另一端以确定另一端的发送窗口大小。该字段与TCP的流量控制服务有关。

【校验和字段】- 16bit

  与IP协议的检验和不同,TCP的这个校验和是针对首部和数据两部分的。

【紧急指针字段】- 16bit

  紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。

  

(3)TCP报文的可选项

  在TCP报文头部的前20个字节是固定的。有时TCP报文也会在报文头部增加一些选项,该部分的长度不固定,不同的应用场景会有所变化。

  该部分的可选项常用的包含但不仅限于有以下几种:

  ① 最大报文传输段(即常提到的MSS): 用于确定每一个TCP报文段中科传输的最大的数据长度(注意,不包括头部)

  ② 窗口扩大选项:TCP的窗口大小最大为64K,在大多数时候这是够用的,但有时候为了提高吞吐量,就需要对窗口扩大,这个时候,就需要使用该选项对窗口进行扩大。

  ③ 时间戳选项:可以用来计算RLL,进而可以用于TCP的拥塞控制。