从本节课开始,我们将分两次课来介绍 TCP 的运输连接管理。
5.8.1 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 连接表,指向发送和接收缓存的指针,指向重传队列的指针,当前发送和接收序号等。之后就要准备接受 TCP 客户进程的连接请求。
此时 TCP 服务器进程就要进入监听状态,等待 TCP 客户进程的连接请求。TCP 服务器进程是被动等待来自 TCP 客户进程的连接请求,而不是主动发起,因此称为被动打开连接。
- TCP 客户进程也是首先创建传输控制块,然后在打算建立 TCP 连接时,向 TCP 服务器进程发送 TCP 连接请求报文段,并进入同步已发送状态。TCP 连接请求报文段首部中的同步位 SYN 被设置为 1,表明这是一个 TCP 连接请求报文段,序号字段 SEQ 被设置了一个初始值 X,作为 TCP 客户进程所选择的初始序号。请注意 TCP 规定,SYN 被设置为 1 的报文段,不能携带数据,但要消耗掉一个序号。由于 TCP 连接建立是由 TCP 客户进程主动发起的,因此称为主动打开连接。
- TCP 服务器进程收到 TCP 连接请求报文段后。如果同意建立连接,则向 TCP 客户进程发送 TCP 连接请求确认报文段,并进入同步已接收状态。该报文段首部中的同部位 SYN 和确认位 ACK 都设置为 1,表明这是一个 TCP 连接请求确认报文段。序号字段 SEQ 被设置了一个初始值 Y,作为 TCP 服务器进程所选择的初始序号,确认号字段 ACK 的值被设置成了 X+1,这是对 TCP 客户进程所选择的初始序号的确认。请注意这报文段也不能携带数据,因为它是 SYN 被设置为 1 的报文段,但同样要消耗掉一个序号
- TCP 客户进程收到 TCP 连接请求确认报文段后,还要向 TCP 服务器进程发送一个普通的 TCP 确认报文段,并进入连接已建立状态。该报文段首部中的确认为 ACK 被设置为 1,表明这是一个普通的 TCP 确认报文段,序号字段 SEQ 被设置为 X+1,这是因为 TCP 客户进程发送的第一个 TCP 报文段的序号为 X 并且不携带数据,因此第二个报文段的序号为 X+1。请注意 TCP 规定,普通的 TCP 确认报文段可以携带数据,但如果不携带数据则不消耗序号。在这种情况下,所发送的下一个数据报文段的序号仍是 X+1,确认号字段 ACK 被设置为 Y+1,这是对 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 客户进程发送 TCP 连接请求,确认报文段,并进入连接已建立状态。该报文段到达 TCP 客户进程,由于 TCP 客户进程并没有发起新的 TCP 连接请求,并且处于关闭状态,因此不会理会该报文段,但 TCP 服务器进程已进入了连接已建立状态,他认为新的 TCP 连接已建立好了,并一直等待 TCP 客户进程发来数据,这将白白浪费 TCP 服务器进程所在主机的很多资源。
练习题,这是计算机专业考研全国统考计算机网络部分 2011 年的题 39,答案是选项 C
如图所示,这是本节课所介绍的 TCP 通过三报文握手建立连接的过程。
根据题意,主机甲中的是 TCP 客户进程,主机乙中的是 TCP 服务器进程,这是主机甲中 TCP 客户进程,像主机乙中 TCP 服务器进程发送的第一个 TCP 段,其首部中的同部位 SYN 的值为 1,序号字段 SEQ 的值就是题目所给的 11220,这是主机乙中 TCP 服务器进程,给主机假装 TCP 客户进程发送的 TCP 连接请求确认报文段,其首部中的同步位 SYN 和确认位 ACK 的值都被设置为 1,表明这是一个 TCP 连接请求确认报文段,确认号字段 ACK 的值是对主机甲中 TCP 客户进程多选择初始序号,11220 的确认,因此为 11221 至此我们就已经可以选出正确答案为选项 C 了。序号字段 SEQ 的值是主机乙装 TCP 服务器进程所选择的初始序号,可由 TCP 服务器进程随意指定,与其他报文段中的值无关。在本题的正确选项 C 中,序号字段 SEQ 的值恰好与确认号字段 ACK 的值同为 11221,这正是本题迷惑大家的地方,使很多同学认为该选项有点别扭。
本节课的内容小结如下:
5.8.2 TCP 的连接释放
本节课我们介绍 TCP 的连接释放,TCP 通过四报文挥手来释放连接。我们来举例说明。
数据传输结束后,TCP 通信双方都可以释放连接,现在 TCP 客户进程和 TCP 服务器进程都处于连接已建立状态。假设使用 TCP 客户进程的应用进程,通知其主动关闭 TCP 连接,TCP 客户进程会发送 TCP 连接释放报文段,并进入终止等待一状态。该报文段首部中的终止位 FIN 和确认为 ACK 的值都被设置为 1,表明这是一个 TCP 连接释放报文段,同时也对之前收到的报文段进行确认。序号 SEQ 字段的值设置为 U 它等于 TCP 客户进程之前已传送过的数据的最后一个字节的序号加一。
请注意 TCP 规定终止为 FIN 等于一的报文段,即使不携带数据也要消耗掉一个序号,确认号 ESSAY 字段的值设置为 v,它等于 TCP 客户进程之前已收到的数据的最后一个字节的序号加一,TCP 服务器进程收到 TCP 连接释放报文段后,会发送一个普通的 TCP 确认报文段,并进入关闭等待状态。该报文段首部中的确认为 ACK 的值,被设置为一,表明这是一个普通的 TCP 确认报文段,序号 SEQ 字段的值设置为 V,它等于 TCP 服务器进程之前以传送过的数据的最后一个字节的序号加 1,这也与之前收到的 TCP 连接释放报文段中的确认号匹配,确认号 ACK 字段的值设置为 U+1,这是对 TCP 连接释放报文段的确认。
TCP 服务器进程这时应通知高层应用进程,TCP 客户进程要断开与自己的 TCP 连接,此时从 TCP 客户进程到 TCP 服务器进程,这个方向的连接就释放了,这时的 TCP 连接属于半关闭状态,也就是 TCP 客户进程已经没有数据要发送了,但 TCP 服务器进程如果还有数据要发送,TCP 客户进程仍要接收,也就是说从 TCP 服务器进程到 TCP 客户进程,这个方向的连接并未关闭,这个状态可能会持续一段时间,TCP 客户进程收到 TCP 确认报文段后,就进入终止等待二状态,等待 TCP 服务器进程发出的 TCP 连接释放报文段。
若使用 TCP 服务器进程的应用进程已经没有数据要发送了,应用进程就要通知其 TCP 服务器进程释放连接。由于 TCP 连接释放是由 TCP 客户进程主动发起的,因此 TCP 服务器进程对 TCP 连接的释放称为被动关闭连接,TCP 服务器进程发送 TCP 连接释放报文段,并进入最后确认状态。该报文段首部中的终止为 FIN 和确认为 ACK 的值,都被设置为 1,表明这是一个 TCP 连接释放报文段,同时也对之前收到的报文段进行确认。现在假定序号 SEQ 字段的值为 W,这是因为在半关闭状态下,TCP 服务器进程可能又发送了一些数据,确认号 ACK 字段的值为 U+1,这是对之前收到的 TCP 连接释放报文段的重复确认。TCP 客户进程收到 TCP 连接释放报文段后,必须针对该报文段发送普通的 TCP 确认报文段,之后进入时间等待状态,该报文段首部中的确认为 ACK 的值,被设置为 1,表明这是一个普通的 TCP 确认报文段,序号 SEQ 字段的值设置为 U+1,这是因为 TCP 客户进程之前发送的 TCP 连接释放报文段,虽然不携带数据,但要消耗掉一个序号,确认号 ACK 字段的值设置为 W+1,这是对所收到的 TCP 连接释放报文段的确认。TCP 服务器进程收到该报文段后就要进入关闭状态,而 TCP 客户进程还要经过两倍的 MSL 后才能进入关闭状态。MSL 的意思是最长报文段寿命,RFC793 文档建议为两分钟,
也就是说 TCP 客户进程进入时间等待状态后,还要经过 4 分钟才能进入关闭状态,这完全是从工程上来考虑的。对于现在的网络 MSL 取为两分钟可能太长了,因此 TCP 允许不同的实现和根据具体情况使用更小的 MSL 值。
那么 TCP 客户进程在发送完最后一个确认报文段后,为什么不直接进入关闭状态,而是要进入时间等待状态,两倍 MSL 后才进入关闭状态,这是否有必要呢?来看这种情况,TCP 服务器进程发送 TCP 连接释放报文段后进入最后确认状态,TCP 客户进程收到该报文段后,发送普通的 TCP 确认报文段,并进入关闭状态,而不是时间等待状态。然而该 TCP 确认报文段丢失了,这必然会造成 TCP 服务器进程,对之前所发送的 TCP 连接释放报文段的超时重传,并仍处于最后确认状态。重传的 TCP 连接释放报文段到达 TCP 客户进程,由于 TCP 客户进程属于关闭状态,因此不理睬该报文段,这必然会造成 TCP 服务器进程反复重传 TCP 连接释放报文段,并一直处于最后确认状态,而无法进入关闭状态。
因此时间等待状态以及处于该状态两倍 MSL 的时长,可以确保 TCP 服务器进程可以收到最后一个 TCP 确认报文段而进入关闭状态。另外 TCP 客户进程在发送完最后一个 TCP 确认报文段后,再经过两倍 MSL 时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的 TCP 连接中不会出现旧连接中的报文段。以上就是 TCP 通过 4 报文挥手释放连接的过程。
最后我们再来看看 TCP 中饱和计时器的作用。设想这样一种情况,TCP 双方已经建立了连接,后来 TCP 客户进程所在的主机突然出现了故障,显然 TCP 服务器进程以后就不能再收到 TCP 客户进程发来的数据,因此应当有措施使 TCP 服务器进程,不要再白白等待下去。换句话说,TCP 服务器进程应该如何发现这种情况?方法就是使用保活计时器、TCP 服务器进程每收到一次 TCP 客户进程的数据,就要重新设置并启动保活计时器,若保活计时器定时周期内未收到 TCP 客户进程发来的数据,则当保活计时器到时后,TCP 服务器进程就向 TCP 客户进程发送一个探测报文段,以后每隔 75 秒钟发送一次,若一连发送 10 个探测报文段,后仍无 TCP 客户进程的响应,TCP 服务器进程就认为 TCP 客户进程所在主机出了故障,接着就要关闭这个连接
本节课的内容小结如下:
标签:报文,确认,TCP,计算机网络,进程,服务器,课堂,连接 From: https://www.cnblogs.com/PeterJXL/p/18214993