tcp

TCP 协议的报文格式

TCP 协议作为传输层协议,只负责将数据从一端可靠地传输到另一端。它处理的是连接的建立、数据的传输顺序和确认信息等内容。TCP 包中包含的内容包括源/目标 IP、端口号、序列号、确认号等,但不包含具体的应用层数据的业务逻辑或命令。

在 TCP/IP 协议栈中,IP 协议层只关心如何使数据能够跨越本地网络边界的问题,而不关心数据如何传输。整体 TCP/IP 协议栈,共同配合一起解决数据如何通过许许多多个点对点通路,顺利传输到达目的地。一个点对点通路被称为一“跳”(hop),通过 TCP/IP 协议栈,网络成员能够在许多“跳”的基础上建立相互的数据通路。

传输层 TCP 协议提供了一种面向连接的、可靠的字节流服务,其数据帧格式,大致如下图所示:
在这里插入图片描述

(一)源端口号

源端口号表示报文的发送端口,占 16 位。源端口和源 IP 地址组合起来,可以标识报文的发送地址。

(二)目的端口号

目的端口号表示报文的接收端口,占 16 位。目的端口和目的 IP 地址相结合,可以标识报文的接收地址。

TCP 协议是基于 IP 协议的基础上传输的,TCP 报文中的源端口号+源 IP,与 TCP 报文中的目的端口号+目的 IP 一起,组合起来唯一性的确定一条 TCP 连接。

(三)序号(Sequence Number)

TCP 传输过程中,在发送端出的字节流中,传输报文中的数据部分的每一个字节都有它的编号。序号(Sequence
Number)占 32 位,发起方发送数据时,都需要标记序号。

序号(Sequence Number)的语义与 SYN 控制标志(Control
Bits)的值有关。根据控制标志(Control Bits)中的 SYN 是否为 1,序号(Sequence
Number)表达不同的含义:

(1)当 SYN = 1 时,当前为连接建立阶段,此时的序号为初始序号 ISN((Initial Sequence
Number),通过算法来随机生成序号;

(2)当 SYN = 0 时在数据传输正式开始时,第一个报文的序号为 ISN +
1,后面的报文的序号,为前一个报文的 SN 值+TCP 报文的净荷字节数(不包含 TCP 头)。比如,如果发送端发送的一个 TCP 帧的净荷为 12byte,序号为 5,则发送端接着发送的下一个数据包的时候,序号的值应该设置为 5+12=17。

在数据传输过程中,TCP 协议通过序号(Sequence
Number)对上层提供有序的数据流。发送端可以用序号来跟踪发送的数据量;接收端可以用序号识别出重复接收到的 TCP 包,从而丢弃重复包;对于乱序的数据包,接收端也可以依靠序号对其进行排序。

(四)确认序号(Acknowledgment Number)

确认序号(Acknowledgment
Number)标识了报文接收端期望接收的字节序列。如果设置了 ACK 控制位,确认序号的值表示一个准备接收的包的序列码,注意,它所指向的是准备接收的包,也就是下一个期望接收的包的序列码。

举个例子,假设发送端(如 Client)发送 3 个净荷为 1000byte、起始 SN 序号为 1 的数据包给 Server 服务端,Server 每收到一个包之后,需要回复一个 ACK 响应确认数据包给 Client。ACK 响应数据包的 ACK
Number 值,为每个 Client 包的为 SN+包净荷,既表示 Server 已经确认收到的字节数,还表示期望接收到的下一个 Client 发送包的 SN 序号,具体的 ACK 值如下图左边的正常传输部分所示。

图:传输过程的确认序号(Acknowledgment Number)值示例图

在上图的左边部分,Server 第 1 个 ACK 包的 ACK
Number 值为 1001,是通过 Client 第 1 个包的 SN+包净荷=1+1000 计算得到,表示期望第 2 个 Client 包的 SN 序号为 1001;Server 第 2 个 ACK 包的 ACK
Number 值为 2001,为 Client 第 2 个包的 SN+包净荷=2001,表示期望第 3 个 Server 包的 SN 为 2001,以此类推。

如果发生错误,假设 Server 在处理 Client 的第二个发送包异常,Server 仍然回复一个 ACK
Number 值为 1001 的确认包,则 Client 的第二个数据包需要重复发送,具体的 ACK 值如上图右边的正常传输部分所示。

只有控制标志的 ACK 标志为 1 时,数据帧中的确认序号 ACK
Number 才有效。TCP 协议规定,连接建立后,所有发送的报文的 ACK 必须为 1,也就是建立连接后,所有报文的确认序号有效。如果是 SYN 类型的报文,其 ACK 标志为 0,故没有确认序号。

(五)头部长度

该字段占用 4 位,用来表示 TCP 报文首部的长度,单位是 4bit 位。其值所表示的并不是字节数,而是头部的所含有的 32bit 的数目(或者倍数),或者 4 个字节的倍数,所以 TCP 头部最多可以有 60 字节(4*15=60)。没有任何选项字段的 TCP 头部长度为 20 字节,所以其头部长度为 5,可以通过 20/4=5 计算得到。

(六)预留 6 位

头部长度后面预留的字段长度为 6 位,作为保留字段,暂时没有什么用处。

(七)控制标志

控制标志(Control
Bits)共 6 个 bit 位,具体的标志位为:URG、ACK、PSH、RST、SYN、FIN。6 个标志位的说明,如下表所示。

标注位 说明
URG 占 1 位,表示紧急指针字段有效。URG 位指示报文段里的上层实体(数据)标记为“紧急”数据。当 URG=1 时,其后的紧急指针指示紧急数据在当前数据段中的位置(相对于当前序列号的字节偏移量),TCP 接收方必须通知上层实体。
ACK 占 1 位,置位 ACK=1 表示确认号字段有效;TCP 协议规定,接建立后所有发送的报文的 ACK 必须为 1;当 ACK=0 时,表示该数据段不包含确认信息。当 ACK=1 时,表示该报文段包括一个对已被成功接收报文段的确认序号 Acknowledgment Number,该序号同时也是下一个报文的预期序号。
PSH 占 1 位,表示当前报文需要请求推(push)操作;当 PSH=1 时,接收方在收到数据后立即将数据交给上层,而不是直到整个缓冲区满。
RST 占 1 位,置位 RST=1 表示复位 TCP 连接;用于重置一个已经混乱的连接,也可用于拒绝一个无效的数据段或者拒绝一个连接请求。如果数据段被设置了 RST 位,说明报文发送方有问题发生。
SYN 占 1 位,在连接建立时用来同步序号。当 SYN=1 而 ACK=0 时,表明这是一个连接请求报文。对方若同意建立连接,则应在响应报文中使 SYN=1 和 ACK=1。 综合一下,SYN 置 1 就表示这是一个连接请求或连接接受报文。
FIN 占 1 位,用于在释放 TCP 连接时,标识发送方比特流结束,用来释放一个连接。当 FIN = 1 时,表明此报文的发送方的数据已经发送完毕,并要求释放连接。

在连接建立的三次握手过程中,若只是单个 SYN 置位,表示的只是建立连接请求。如果 SYN 和 ACK 同时置位为 1,表示的建立连接之后的响应。

(八)窗口大小:

长度为 16 位,共 2 个字节。此字段用来进行流量控制。流量控制的单位为字节数,这个值是本端期望一次接收的字节数。

(九)校验和:

长度为 16 位,共 2 个字节。对整个 TCP 报文段,即 TCP 头部和 TCP 数据进行校验和计算,接收端用于对收到的数据包进行验证。

(十)紧急指针:

长度为 16 位,2 个字节。它是一个偏移量,和 SN 序号值相加表示紧急数据最后一个字节的序号。

以上十项内容是 TCP 报文首部必须的字段,也称固有字段,长度为 20 个字节。接下来是 TCP 报文的可选项和填充部分。

(十一)可选项和填充部分

可选项和填充部分的长度为 4n 字节(n 是整数),该部分是根据需要而增加的选项。如果不足 4n 字节,要加填充位,使得选项长度为 32 位(4 字节)的整数倍,具体的做法是在这个字段中加入额外的零,以确保 TCP 头是 32 位(4 字节)的整数倍。

最常见的选项字段是 MSS(Maximum Segment
Size 最长报文大小),每个连接方通常都在通信的第一个报文段(SYN 标志为 1 的那个段)中指明这个选项字段,表示当前连接方所能接受的最大报文段的长度。

由于可选项和填充部分不是必须的,所以 TCP 报文首部最小长度为 20 个字节。

至此,TCP 报文首部的字段,就全部介绍完了。TCP 报文首部的后面,接着的是数据部分,不过数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据,比如在处理超时的过程中,也会发送不带任何数据的报文段。

总体来说,TCP 协议的可靠性,主要通过以下几点来保障:

(1)应用数据分割成 TCP 认为最适合发送的数据块。这部分是通过 MSS(最大数据包长度)选项来控制的,通常这种机制也被称为一种协商机制,MSS 规定了 TCP 传往另一端的最大数据块的长度。值得注意的是,MSS 只能出现在 SYN 报文段中,若一方不接收来自另一方的 MSS 值,则 MSS 就定为 536 字节。一般来讲,MSS 值还是越大越好,这样可以提高网络的利用率。

(2)重传机制。设置定时器,等待确认包,如果定时器超时还没有收到确认包,则报文重传。

(3)对首部和数据进行校验。

(4)接收端对收到的数据进行排序,然后交给应用层。

(5)接收端丢弃重复的数据。

(6)TCP 还提供流量控制,主要是通过滑动窗口来实现流量控制。

至此 TCP 协议的数据帧格式介绍完了。接下来开始为大家重点介绍:TCP 传输层的三次握手建立连接,四次挥手释放连接。

TCP 三次握手和四次挥手

三次握手

TCP 连接的建立时,双方需要经过三次握手,具体过程如下:

(1)第一次握手:Client 进入 SYN_SENT 状态,发送一个 SYN 帧来主动打开传输通道,该帧的 SYN 标志位被设置为 1,同时会带上 Client 分配好的 SN 序列号,该 SN 是根据时间产生的一个随机值,通常情况下每间隔 4ms 会加 1。除此之外,SYN 帧还会带一个 MSS(最大报文段长度)可选项的值,表示客户端发送出去的最大数据块的长度。

(2)第二次握手:Server 端在收到 SYN 帧之后,会进入 SYN_RCVD 状态,同时返回 SYN+ACK 帧给 Client,主要目的在于通知 Client,Server 端已经收到 SYN 消息,现在需要进行确认。Server 端发出的 SYN+ACK 帧的 ACK 标志位被设置为 1,其确认序号 AN(Acknowledgment
Number)值被设置为 Client 的 SN+1;SYN+ACK 帧的 SYN 标志位被设置为 1,SN 值为 Server 端生成的 SN 序号;SYN+ACK 帧的 MSS(最大报文段长度)表示的是 Server 端的最大数据块长度。

(3)第三次握手:Client 在收到 Server 的第二次握手 SYN+ACK 确认帧之后,首先将自己的状态会从 SYN_SENT 变成 ESTABLISHED,表示自己方向的连接通道已经建立成功,Client 可以发送数据给 Server 端了。然后,Client 发 ACK 帧给 Server 端,该 ACK 帧的 ACK 标志位被设置为 1,其确认序号 AN(Acknowledgment
Number)值被设置为 Server 端的 SN 序列号+1。还有一种情况,Client 可能会将 ACK 帧和第一帧要发送的数据,合并到一起发送给 Server 端。

(4)Server 端在收到 Client 的 ACK 帧之后,会从 SYN_RCVD 状态会进入 ESTABLISHED 状态,至此,Server 方向的通道连接建立成功,Server 可以发送数据给 Client,TCP 的全双工连接建立完成。
在这里插入图片描述

四次挥手

业务数据通信完成之后,TCP 连接开始断开(或者拆接)的过程,在这个过程中连接的每个端的都能独立地、主动的发起,断开的过程 TCP 协议使用了四路挥手操作。

(1)第一次挥手:主动断开方(可以是客户端,也可以是服务器端),向对方发送一个 FIN 结束请求报文,此报文的 FIN 位被设置为 1,并且正确设置 Sequence Number(序列号)和 Acknowledgment Number(确认号)。发送完成后,主动断开方进入 FIN_WAIT_1 状态,这表示主动断开方没有业务数据要发送给对方,准备关闭 SOCKET 连接了。

(2)第二次挥手:正常情况下,在收到了主动断开方发送的 FIN 断开请求报文后,被动断开方会发送一个 ACK 响应报文,报文的 Acknowledgment Number(确认号)值为断开请求报文的 Sequence Number
(序列号)加 1,该 ACK 确认报文的含义是:“我同意你的连接断开请求”。之后,被动断开方就进入了 CLOSE-WAIT(关闭等待)状态,TCP 协议服务会通知高层的应用进程,对方向本地方向的连接已经关闭,对方已经没有数据要发送了,若本地还要发送数据给对方,对方依然会接受。被动断开方的 CLOSE-WAIT(关闭等待)还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。

主动断开方在收到了 ACK 报文后,由 FIN_WAIT_1 转换成 FIN_WAIT_2 状态。

(3)第三次挥手:在发送完成 ACK 报文后,被动断开方还可以继续完成业务数据的发送,待剩余数据发送完成后,或者 CLOSE-WAIT(关闭等待)截止后,被动断开方会向主动断开方发送一个 FIN+ACK 结束响应报文,表示被动断开方的数据都发送完了,然后,被动断开方进入 LAST_ACK 状态。

(4)第四次挥手:主动断开方收在到 FIN+ACK 断开响应报文后,还需要进行最后的确认,向被动断开方发送一个 ACK 确认报文,然后,自己就进入 TIME_WAIT 状态,等待超时后最终关闭连接。处于 TIME_WAIT 状态的主动断开方,在等待完成 2MSL 的时间后,如果期间没有收到其他报文,则证明对方已正常关闭,主动断开方的连接最终关闭。

被动断开方在收到主动断开方的最后的 ACK 报文以后,最终关闭了连接,自己啥也不管了。

在这里插入图片描述

处于 TIME_WAIT 状态的主动断开方,在等待完成 2MSL 的时间后,才真正关闭连接通道,其等待的时间为什么是 2MSL 呢?

2MSL 翻译过来就是两倍的 MSL。MSL 全称为 Maximum Segment
Lifetime,指的是一个 TCP 报文片段在网络中最大的存活时间,具体来说,2MSL 对应于一次消息的来回(一个发送和一个回复)所需的最大时间。如果直到 2MSL,主动断开方都没有再一次收到对方的报文(如 FIN 报文),则可以推断 ACK 已经被对方成功接收,此时,主动断开方将最终结束自己的 TCP 连接。所以,TCP 的 TIME_WAIT 状态也称为 2MSL 等待状态。

有关 MSL 的具体的时间长度,在 RFC1122 协议中推荐为 2 分钟。在 SICS(瑞典计算机科学院)开发的一个小型开源的 TCP/IP 协议栈——LwIP 开源协议栈中 MSL 默认为 1 分钟。在源自 Berkeley 的 TCP 协议栈实现中 MSL 默认长度为 30 秒。总体来说,TIME_WAIT(2MSL)等待状态的时间长度,一般维持在 1-4 分钟之间。

通过三次握手建立连接和四次挥手拆除连接,一次 TCP 的连接建立及拆除,至少进行 7 次通信,可见其成本是很高的。

posted @ 2024-10-16 11:51  r_0xy  阅读(93)  评论(0)    收藏  举报