TCP的运输连接管理
文章目录
- TCP的运输连接管理
- TCP报文格式简介
- 首部各个字段的含义
- 控制位(flags)
- TCP的连接建立
- 抓包验证
- 一些细节及解答
- TCP连接释放
- 抓包验证
- 一些细节及解答
- 参考
TCP是面向连接的协议。运输连接是用来传送TCP报文的。TCP运输连接的建立和释放时每一次面向连接的通信中必不可少的过程。因此,运输连接就有三个阶段,即: 连接建立、 数据传输、 连接释放。运输连接的管理就是使运输连接的建立和释放都能正常运行。
TCP的连接是一条 虚连接(也就是 逻辑连接 )
在TCP连接建立的过程中要解决以下三个问题:
- 要使每一方能够确知对方的存在。
- 要允许双方协议一些参数(如最大窗口值、是否使用窗口扩大选项和时间戳选项以及服务质量等)
- 能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配。
TCP连接蚕蛹客户服务器方式。主动放弃连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫做服务器。
TCP最主要的特点
- TCP是面向连接的运输层协议。 这就是说在传送数据前必须先建立TCP连接。在传送完数据后必须释已经建立的TCP连接。
- 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点(一对一)
- TCP 提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
- TCP提供全双工通信。 TCP允许通信双档的应用进程在任何时候都能发送数据。TCP连接的两段都设有发送缓存和接受缓存,用来临时存放双向通信的数据。
- 面向字节流 TCP中的“流”指的是 流入到进程或从进程流出的字节序列。
面向字节流
的含义是:虽然程序和TCP的交互是一次一个数据(大小不等),但TCP把应用程序交下来的数据仅仅看成是一串无结构的字节流。
TCP报文格式简介
TCP虽然是面向字节流的,但TCP传送的数据单元却是报文段。一个TCP报文段的分为首部和数据两部分,而TCP的全部功能都体现在它首部中各个字段的作用。下面我们就来看一下TCP报文段首部格式。
首部各个字段的含义
首部固定部分个字段的意思如下:
-
源端口和目的端口 各占2个字节,分别写入源端口号和目的端号。
-
序号(seq) 占4字节。序号范围是 [ 0 , 2 32 − 1 ] [0, 2^{32} - 1] [0,232−1],共 2 32 2^{32} 232个序号。序号增加到 [ 0 , 2 32 − 1 ] [0, 2^{32} - 1] [0,232−1]后,下一个序号就又回到0。
-
确认号(ack) 占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。
若确认号 = N, 则表明:到序号 N - 1为止的所有数据都已正确收到。
-
数据偏移 占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。换个说法是这个字段指出了TCP报文段的首部长度。
首部最小长度为20字节,因此数据偏移字段的最小值为 ( 0101 ) 2 (0101)_2 (0101)2.
首部最长长度为60字节,因此数据偏移字段的最小值为 ( 1111 ) 2 (1111)_2 (1111)2.
-
保留 占6位,保留为今后使用,但目前应置为0。
-
控制位(flags) 有6个控制位,用于说明本报文段的性质。 具体含义见下。
-
窗口 占2字节。窗口值是 [ 0 , 2 16 − 1 ] [0, 2^{16} - 1] [0,216−1]之间的整数。窗口指的是发送本报文段的一方的接收窗口。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许发送的数据量(以字节为单位)。有这个限制的原因是接收方的数据缓存空间是优先的。窗口值作为接收方让发送方设置其发送窗口的依据。
窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着。
-
检验和 占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
-
紧急指针 占2字节。紧急指正仅在URG = 1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此,紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时。值得注意的是,即使窗口为零时也可发送紧急数据。
-
选项 长度可变,最长可达40字节。当没有使用“选项”时,TCP的首部长度是20字节。
随着互联网的发展出现了多个选项:
-
最大报文段长度 MSS. MSS是每一个TCP报文段中的**数据字段的最大长度**(不包含首部)。(最初只有这个)
-
窗口扩大 窗口扩大选项占3字节,其中一个字节表示移位值S.新窗口值等于TCP首部中的窗口位数从16增大到(16 + S)。移位值允许使用的最大值是14 ,相当于窗口最大值增大到 2 16 + 14 − 1 = 2 30 − 1 2^{16 + 14} - 1 = 2^{30} - 1 216+14−1=230−1。
为了使像卫星信道的网络提高吞吐量,需要更大的窗口。
-
时间戳 占10字节,其中最主要的字段是时间戳值(4字节)和时间戳回送回答字段(4字节)
发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确计算出RTT。
时间戳的两个功能:
① 用来计算往返时间RTT
② 用于处理TCP序号超过 2 32 2^{32} 232的情况,这又称为 防止序号绕回 PAWS (Protect Against Wrapped Sequence numbers)
-
控制位(flags)
-
紧急 URG(URGent) 当 URG = 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送,而不需要按原来的排队顺序来传送。例如,用户发出的中断命令,中断在远地的程序运行。
当URG置1时,发送方TCP就把紧急数据插入到报文段数据的最前面,而在紧急数据后面的数据任然是普通数据。这需要与首部中的紧急指针字段配合使用。
-
确认 ACK 仅当ACK = 1时确认号字段才有效,当ACK = 0 时,确认号无效。TCP规定,在建立连接后所有传输的报文段都必须把ACK置为1.
-
推送 PSH 当将PSH置为1,并发送出该TCP时。接收方就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
-
复位 RST 当RST = 1时,表明TCP连接中出现严重错误,必须释放连接。RST还用来拒绝一个非法报文段或拒绝打开一个连接。RST也可以称为重建位或重置位。
-
同步 SYN (SYNchronization) 当SYN置为1时,表明这是一个连接请求报文段。
-
终止 FIN 用来释放一个连接。当FIN = 1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
TCP的连接建立
TCP建立连接的过程叫做握手,握手时需要在客户机和服务器之间交换三个报文段(也可以是四个)TCP报文段。下图为三报文握手建立TCP连接的过程。
如果在上一小节对TCP首部报文各字段都有了认识。下面对上面三条线的意思做如下语义化:
- A:你好,可以建立连接嘛?我的报文段序号为x。
- B:好的,接受你向我建立连接,期待你序号为x+1的报文段。我也可以向你建立连接嘛?我的报文序号为y。
- A:接受你发起的连接,期待你发送的序号为y+1的报文段,我发送数据的序号是x+1.
抓包验证
下面是通过抓包工具抓到的一些数,可以用来分析TCP的三次握手:
在图中红框选中显示的是完整的TCP连接的“三次握手”过程。
在6068->80过程中,6068是客户端端口,80是服务器的端口。在6068和80端口之间来回就是“三次握手”的过程。
可以看到“第一次握手”客户端发送的TCP报文中以[SYN]作为标志位,并且客户端序号seq = 0.
在第二次中服务端返回的TCP报文中以[SYN, ACK]作为标志位。同时发送服务端的序号seq = 0,确认号ack = 1(是”第一次握手“中客户端序号seq值 + 1)
“第三次握手”中客户端再向服务器发送的TCP报文中以ACK作为标志位。同时携带客户端序号seq = 1(第二次握手中服务器确认号ack的值);确认号ack = 1(第二次握手中服务端序号seq + 1)
通过上面三步客户端和服务端就建立了连接,符合前面的TCP连接的示意图。
一些细节及解答
为什么A最后还要发送一次确认呢?(为什么需要最后一次握手)
这主要是为了防止已失效的连接请求报文段突然又传到了B,因而产生了错误。
所谓的已失效请求报文段可以在以下场景中产生:
A先发送的连接请求报文,因种种原因延迟了。于是A又发送了请求连接报文,并且成功经历了连接、数据传送、断开连接。在断开连接之后A第一次发送的请求报文才刚到,于是B开始向A发出确认报文段,但是A并没有发出新的建立连接的请求,因此不会理睬B的确认。如果缺少最后一次握手,会导致B发出建立连接报文之后就认为连接建立,而A实际上并没有同意连接的建立。
TCP连接释放
四次挥手的理解:
(1) 首先客户端想要释放连接,向服务器端发送一段TCP报文,其中:
- 标记位为FIN,表示"请求释放连接"
- 序号为seq = u
- 随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。
(2) 服务器接收到从客户端发出的TCP报文后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:
- 标记位ACK,表示“接收到客户端发送的释放连接的请求”
- 序号位seq = v
- 确认号为ack = u + 1,表示是在收到客户端报文的基础上,将其序号值加q作为本段报文确认号ack的值;
- 随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的TCP报文后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段
(3) 服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
- 标记位为FIN,ACK,表示“已经准备好释放连接了”。注意这里的ACK并不是确认收到服务端的确认报文。
- 序号为seq = w
- 确认号为ack = u + 1,表示是在收到客户端报文的基础上,将其序号seq值加1作为本报文确认号ack的值。
随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。
(4) 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务端发送一段报文,其中:
- 标记位ACK,表示接收到服务器准备号释放连接的信号
- 序号为seq = u + 1,表示在收到了服务器端报文的基础上,将其确认号ack值作为本报文序号的值。
- 确认号为ack = w + 1,表示是在收到了服务器端报文的基础上,将其序号seq值作为本段报文确认号的值
随后客户端开始在TIME-WAIT阶段等待2MSL.
抓包验证
上图为借助抓包工具,抓取到的TCP的四次挥手的过程。可以照前面的示意图和文字来看。发现与前面的描述一致。
一些细节及解答
为什么客户端在TIME-WAIT阶段要等2MSL?
这有两个理由:
① 为了保证A发送的最后一个ACK报文能够到达B.因为A发送的最后这个ACK报文可能丢失。如果A直接进入到CLOSE阶段跳过TIME-WAIT阶段的话,B在无法收到确认断开的报文段重新发送请求断开的报文段时,A将无法收到因为此时连接已经断开。
② 防止上一节提到的“已失效的连接请求报文段”出现在本连接中。在A发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中小时。这样就可以使下一个新的连接中不会出席那这种旧的连接请求报文段。
参考
-
《计算机网络 第7版》
-
详解 TCP 连接的“ 三次握手 ”与“ 四次挥手 ” (baidu.com)
-
TCP报文段的首部格式