TCP报文结构和功能简析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP报文结构和功能简析相关的知识,希望对你有一定的参考价值。

参考技术A

TCP:传输、 控制 、协议。

TCP与UDP最大却别就在那个 C 上面,它充分实现了数据传输时各种控制功能。可以进行丢包 重发控制 ,还可以对次序乱掉的数据包进行 顺序控制 ,还能 控制传输流量 ,这些是UDP中没有的。即T C P 提供一种面向连接的、可靠的字节流服务。

TCP是一中面向有链接的协议,只有在确认对端存在的时候,才会发送分数据,从而也可以控制通信流量的浪费。

什么是可靠的传输: 不丢包、不损坏、不乱序、不重复。

TCP通过 校验和 序列号 确认应答 重发控制 连接管理 以及 窗口控制 等机制来实现可靠传输。

接收端查询就收数据TCP首部中的序号和数据长度。将自己下一步应该接受的序列号作为确认应答返送回去。就这样,通过序列号和确认应答,TCP实现可靠传输。

一般使用TCP首部用于控制的字段来管理连接。一个连接的建立和断开,正常过程中,至少需要来回共7个包才能完成。

TCP首部的数据结构如图所示:

TCP包首部

为了便于理解,忽略选项部分,固定首部通常为20个字节,将按作用分类分析。

前4个字节 来标识了发送方的端口号和接收方的端口号,即该数据包由谁发送,由谁接收。前2个字节标识源端口号,紧接着2个字节标识目的端口号。

即发送方:(11111111,1111111) 2 = (65535) 10 ,除去0~1023.

即接收方:(11111111,1111111) 2 = (65535) 10 ,除去0~1023.

TCP是面向字节流的。 在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。长度为4字节,序号是32bit的无符号数,序号到达2 32 - 1后又从0开始。

ack :确认序号, <u style="box-sizing: border-box;">即确认字节的序号</u> ,更确切地说,是 发送确认的一端 所期望收到的下一个序号。

所谓的 发送确认的一端 就是将确认信息发出的一端。比如第二次握手的 S 端就是 发送确认的一端

确认序号为上次接收的最后一个字节序号加1.只有确认标志位( ACK )为1的时候,确认序号才有效。

也叫首部长度,占4个bit,它指出TCP报文段的 数据 起始处距离TCP报文段的起始处有多远。

TCP报文结构

由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。

“首部长度”是4位二进制数,单位是 32位字 ,能表示的最大十进制数字是15。

(1111) 2 =(15) 10 ,即是15个32位,一个32位是4个字节,因此数据偏移的最大值是15 4=60个字节,这也是TCP首部的最大字节。因为固定首部的存在,数据偏移的值最小为 20个字节 ,因此选项长度不能超过 40字节 *(减去20个字节的固定首部)。

占6位,保留为今后使用,但目前应置为0。

当URG=1时,表明紧急指针字段有效。

它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。

例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。

当URG置为1时,应用进程就告诉TCP有紧急数据要传送。于是TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中 紧急指针 (Urgent Pointer)字段配合使用。

仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。

当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。

当RST=1时,表明TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。

在连接建立时用来同步序号。当 SYN=1 ACK=0 时,表明这是一个 连接请求报文段 。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。

因此 SYN=1 就表示这是一个连接请求或连接接受报文。

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

占2字节。窗口值是(0,2 16 -1)之间的整数。

窗口指的是发送本报文段的一方的接受窗口(而不是自己的发送窗口),窗口大小是给对方用的。

窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方一次发送的数据量(以字节为单位)。

之所以要有这个限制,是因为接收方的数据缓存空间是有限的。

总之,窗口值作为接收方让发送方设置其发送窗口的依据。

例如,A发送了一个报文段,其确认号是3000,窗口字段是1000.这就是告诉对方B:“从3000算起,A接收缓存空间还可接受1000个字节数据,字节序号是3000-3999”,可以想象到河道的阀门。

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

占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。

占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据) 。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为0时也可以发送紧急数据。

长度可变,最长可达40个字节。当没有使用“选项”时,TCP的首部长度是20字节。

最大报文段长度(MSS:Maximum Segment Size)表示TCP传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的MSS。

当建立一个连接时,每一方都有用于通告它期望接收的MSS选项(MSS选项只能出现在SYN报文段中),如果一方不接收来自另一方的MSS值,则MSS就定为默认值536字节(这个默认值允许20字节的IP首部和20字节的TCP首部以适合576字节IP数据报) 。

为什么要规定一个最大报文长度MSS呢?

这并不是考虑接受方的接收缓存可能存放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。

我们知道,TCP报文段的数据部分,至少要加上40字节的首部( TCP首部20字节 IP首部20字节 ,这里还没有考虑首部中的可选部分)才能组装成一个 IP数据报

若选择较小的MSS长度,网络的利用率就降低。设想在极端情况下,当TCP报文段只含有1字节的数据时,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,对网络的利用率就不会超过1/41。到了数据链路层还要加上一些开销。但反过来,若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片组成成原来的TCP报文段,当传输出错时还要进行重传,这些也都会使开销增大。

因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。

由于IP数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要的分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节

后来又增加了几个选项如窗口扩大选项、时间戳选项等。

窗口扩大选项是为了扩大窗口。

我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。

窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2 (16+14)-1=2 30-1。

窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。

时间戳选项占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:

第一、 用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。

第二、 用于处理TCP序号超过2 32 的情况,这又称为防止序号绕回PAWS。我们知道,TCP报文段的序号只有32位,而每增加2 32 个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。例如,当使用1.5Mbit/s的速度发送报文段时,序号重复要6小时以上。但若用2.5Gbit/s的速率发送报文段,则不到14秒钟序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。

功能 性能 的角度去理解

三次握手建立连接

第一次:

C S 发送一个 建立连接 的请求。此过程中携带一些报文属性信息,这些信息,存在于报文首部,有初始化用的信息,比如,有用于认证的信息。

初始化信息:如报文序列号、

SYN: TCP在数据通信之前,通过TCP首部发送的一个 SYN 标志位,作为建立连接的请求等待接收方确认应答。如果 S 发来确认应答,则认为可以进行数据通信,否则,就不能进行通信。

TCP规定:****SYN=1 的报文段不能携带数据,但是要 消耗掉一个序号 :seq=x。

这个时候 C 进入 SYN-SENT ( 同步已发送 )状态。

第二次:

S 收到 C 请求后,如果同意建立连接,则向 C 返回确认信息:将 SYN ACK 都置 1 ,确认号为 ack=seq+1 (seq来自客户端),并携带自己的 初始化,同时用于认证的信息S

同理: SYN=1 的报文段不能携带数据,但是要 消耗掉一个序号 :seq=y。

这个时候 S 进入 SYN-RCVD ( 同步已接收 )状态。 C 收到 S 返回的确认信息后,进入 ESTABLISHED (已建立连接)的状态,

第三次:

C 收到 S 返回的确认信息后,向 S 再一次发送确认报文。 ACK 置为 1 ,确认号 ack=seq+1 (seq来自 S ),自己的 seq=x+1

TCP规定: ACK报文可以携带数据。但是,如果不携带数据,则不消耗序号,这时,下一数据报文段的序号仍是 seq=x+1 服务器 收到 客户端 返回的确认信息后,也进入 ESTABLISHED (已建立连接)的状态,

从功能角度去考虑前两次握手,从性能的角度去理解为什么需要第三次握手。

有第三次,是考虑到一种错误情况: 假设 C 发了一请求建立连接的报文,长时间未收到 S 的确认报文,则 C 会重发,这个时候 S 与之建立连接、完成数据通信、关闭了连接,这个时候 C 第一发出的请求建立连接的报文到达了 S , S 则会等待 C 发送数据,实际上 C 已经 CLOSED 了, S 就一直在这等待,浪费资源,

确切地说,应该是至少四次数据交互才能实现一个连接的彻底关闭。关闭连接,需要四个报文来指示关闭。

TCP是全双工通信的,所以在一端发送数据完毕后,还具有接收另一端的数据的能力,这就所谓的半关闭。

四次挥手

举个例子 :如果 C 的数据已经发送完毕, C 是不能立即关闭的,因为建立连接的通信双方是平等的。

C 首先告诉 S :“数据发送完毕“,这个消息在TCP报文的首部由 FIN 来标识,让 S 知道 C 是准备断开连接了。这是第一次挥手。

S 收到 C 发来的 FIN 标识的报文后,要给 C 端恢复一个 确认FIN 的消息,告诉 C 说,知道你的数据发完了。这是第二次挥手。

这个时候,如果 S 端的数据也发送完毕了,就给 C 发一个 FIN=1 报文。这是第三次挥手。

C 收到 S 发来的 FIN 标识的报文后,要给 S 端恢复一个 确认FIN 的消息,告诉 C 说,知道你的数据发完了。这是第四次挥手。

然后就彻底断开连接了。

TCP的状态变迁图

TCP之报文首部格式

  • TCP虽然是面向字节流的,但TCP传输的数据单元却是报文段;
  • 一个TCP报文段分为数据和首部两部分,而TCP的全部功能都体现在它首部中各字段的作用;
  • TCP报文段首部前20个字节是固定的,后面有4n个字节是根据需要而增加的选项(n是整数)。因此TCP首部的最小长度是20个字节。

技术图片

技术图片
TCP首部中各字段的含义如下:
  1. 源端口和目的端口:各占2个字节.端口是传输层和应用层的服务接口。传输层的复用和分用功能都有要通过端口才能实现。
  2. 序号:占4个字节,序号范围是(0,2^32 - 1),共2^32(即4294967296)个序号。序号增加到2^32-1后,下一个序号就又回到0。也就是说,序号使用mod 2^32运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号是301,而接待的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的序号也叫“报文段序号”。
  3. 确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。注意,现在确认号不是501,也不是700,而是701。
    • 若确认号为N,则表明,到序号N-1为止的所有数据都已正确收到。
  1. 数据偏移(即首部长度):占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的,但应注意,“数据偏移”的单位是32位字(即以4字节的字为计算单位)。由于4位二进制数能表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节)。
  2. 保留:占6位,保留为今后使用,但目前应置为0。
  3. 紧急URG(URGent):占1位, 当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。
  4. 确认ACK(ACKnowledgment):占1位, 仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。
  5. 推送PSH(Push):占1位,当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。
  6. 复位RST(ReSet):占1位,当RST=1时,表名TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。
  7. 同步SYN(SYNchronization):占1位,在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1,因此SYN置为1就表示这是一个连接请求或连接接受报文。
  8. 终止FIN(FINish):占1位,用来释放一个连接。当FIN=1时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。
  9. 窗口:占2个字节,窗口值是(0,2^16-1)之间的整数。窗口指的是发送本报文段的一方的接受窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。
    • 例如,发送了一个报文段,其确认号是701,窗口字段是1000.这就是告诉对方:“从701算起,我(即发送方报文段的一方)的接收缓存空间还可接受1000个字节数据(字节序号是701~1700),你在给我发数据时,必须考虑到这一点。”
    • 窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化。
  1. 检验和:占2个字节,检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。
  2. 紧急指针:占2个字节,紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据) 。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为0时也可以发送紧急数据。
  3. 选项:长度可变,最长可达4字节。当没有使用“选项”时,TCP的首部长度是20字节。其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*4-20=40字节。
    • MSS最大报文段长度(Maxium Segment Size):TCP最初只规定了一种选项,即最大报文段长度MSS(Maximum Segment Szie)。注意MSS这个名词含义。MSS是每一个TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是整个TCP报文段的最大长度,而是“TCP报文段长度减去TCP首部长度”。
    • 为什么要规定一个最大报文长度MSS呢
      • 这并不是考虑接受方的接收缓存可能存放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。我们知道,TCP报文段的数据部分,至少要加上40字节的首部(TCP首部20字节和IP首部20字节,这里还没有考虑首部中的可选部分)才能组装成一个IP数据报。若选择较小的MSS长度,网络的利用率就降低。设想在极端情况下,当TCP报文段只含有1字节的数据时,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,对网络的利用率就不会超过1/41。到了数据链路层还要加上一些开销。但反过来,若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片组成成原来的TCP报文段,当传输出错时还要进行重传,这些也都会使开销增大。
      • 因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。由于IP数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要的分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节。
    • 其他选项:
      • 窗口扩大选项(Windows Scaling):是为了扩大窗口。我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。
        • 窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2^(16+14)-1=2^30-1。
        • 窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。
      • 时间戳选项(Timestamps):占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:  
        • 用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。
        • 用于处理TCP序号超过2^32的情况,这又称为防止序号绕回PAWS。我们知道,TCP报文段的序号只有32位,而每增加2^32个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。例如,当使用1.5Mbit/s的速度发送报文段时,序号重复要6小时以上。但若用2.5Gbit/s的速率发送报文段,则不到14秒钟序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。
      • SACK选择确认项(Selective Acknowledgements):用来确保只重传缺少的报文段,而不是重传所有报文段。比如主机A发送报文段1、2、3,而主机B仅收到报文段1、3。那么此时就需要使用SACK选项来告诉发送方只发送丢失的数据。那么又如何指明丢失了哪些报文段呢?使用SACK需要两个功能字节。一个表示要使用SACK选项,另一个指明这个选项占用多少字节。描述丢失的报文段2,是通过描述它的左右边界报文段1、3来完成的。而这个1、3实际上是表示序列号,所以描述一个丢失的报文段需要64位即8个字节的空间。那么可以推算整个选项字段最多描述(40-2)/8=4个丢失的报文段。
      • NOP(NO-Operation):它要求选项部分中的每种选项长度必须是4字节的倍数,不足的则用NOP填充。同时也可以用来分割不同的选项字段。如窗口扩大选项和SACK之间用NOP隔开。
  1. 填充:为了使整个首部长度是4字节的整数倍。
 

以上是关于TCP报文结构和功能简析的主要内容,如果未能解决你的问题,请参考以下文章

TCP报文结构和长短连接

tcp 报文段结构

tcp 报文段结构

报文分析4TCP协议的头结构

TCP头部结构

HTTP 报文结构