从零开始的计网学习——运输层(计网TCP/UDP协议部分,面试核心、高频考点,必读!)

5.1 运输层概述

  • 本系列之前的课程所介绍的计算机网络体系结构中的物理层、数据链路层以及网络层之间他们共同解决了将主机通过异构网络互连起来所面临的问题,实现了主机到主机之间的通信
  • 但是实际上在计算机网络中进行通信的真正实体是位于通信两端的主机中的进程

因此运输层协议的功能就出现了:

  • 如何为运行在不同主机上的应用进程提供直接的通信服务?
  • 运输层协议又被称为端到端协议

网络层和运输层的作用范围如下:
网络层和运输层作用范围

网络层及以下层是为了实现主机到主机的通信


运输层是为了实现进程与进程间通信。(AP便为进程的缩写

运输层简单传输过程:
运输层简单传输过程

首先先明确逻辑通信的概念:


“逻辑通信”是指运输层之间的通信使人感觉是沿水平方向传送数据,但事实上,这两条数据并没有一条水平方向的物理连接,要传送的数据是沿着图中上下多次的虚线方向传送

假设进程Ap1与Ap4之间进行基于网络的通信,他们通信的简单过程如下:

  1. 根据不同的进程,在运输层选择使用不同的端口

  2. 通过网络层及其下层来传输应用层报文

  3. 将收到的应用层报文到达接收方的运输层后,通过不同的端口交付给应用层中相应的应用进程

值得注意的是:这里端口并不是指看得见、摸得着的物理端口而是指用来区分不同应用进程的标识符

运输层屏蔽下面核心细节

5.2 运输层端口号、复用和分用的概念

端口号

首先明白为什么要用到端口号:

  • 在操作系统中 ,运行在计算机上的进程使用进程标识符PID来标志,但是因特网上的计算机并不是使用统一的操作系统,不同的操作系统使用不同格式的进程标识符
  • 为了使运行不同系统的计算机的应用进程之间能够进行网络通信,就必须使用统一的方法来对TCP/IP体系的应用进程进行标识。也就是使用端口号。
  • TCP/IP体系的运输层使用端口号来区分应用层的不同应用进程。

端口号的知识

发送方的复用和接收方的分用

  • 复用可以理解为多个进程重复使用一个协议进行应用报文的封装
  • 分用可以理解为一个封装好的应用报文根据某协议进行解析成不同的进程应用报文

例如:
发送方复用和接收方分用

在发送方中,多个进程通过端口利用一个运输层协议将数据封装成报文后发送,这就称为发送方复用,不同协议就叫不同协议复用,如图中的UDP复用。


在IP复用中也会根据协议字段的不同将其使用不同协议再次进行封装。


在接收方中,利用一个协议,将用报文解析成不同数据,将数据根据端口发送不同进程,这就称为接收方分用


在IP分用中也会根据协议字段的不同将其使用不同协议进行解析。

在TCP/IP体系的应用层常用协议的运输层熟知端口号:运用层熟知端口号

针对上述知识,我们对一个域名访问中的运输层传输流程进行解读:

首先先认识在一次运输层传输中的主要路由器:
运输层传输中的主要路由器

DNS服务器:记录有某域名所对应的IP地址,在输入网页域名后,在hosts中找不到网页对应的IP地址时,就要通过DNS服务器获取域名对应的IP地址

Web服务器:某域名的服务器,也就是前面几章所说的目的主机,在访问域名时IP数据报最终即使到达Web服务器,服务器进行响应

假如我们在浏览器中输入某域名:
输入某域名

点击回车键开始访问。


若此时在本地hosts缓存中有该域名的IP地址,直接发送带有目的地址的IP数据报

若计算机中没有该域名对应的IP地址,进行以下操作:

  1. 构建DNS请求报文:
    构建DNS请求报文

先构建DNS请求报文数据,此处用抽象的文字表示。


然后在空闲的短暂端口中随机选择一个端口来表表示本进程。


因为DNS协议请求是熟悉端口之一,根据上面的常见端口熟悉协议可以查找到,DNS协议的端口为53。

  1. 将该UDP请求数据报通过以太网发送给DNF服务器。
    发送UDP请求数据报给DNS服务器

DNS服务器接收到请求数据报文后,从中解封出UDP用户数据报
解封出用户数据报
从数据报的目的端口知道目的端口为53后,服务器会将数据载荷部分(DNS请求报文)交给53端口对应的进程进行处理,此例中也就是DNS服务器端进程。


DNS服务器端进程解析DNS查询请求报文的内容,然后按照其要求查找对应的IP地址。查找到后会发送DNS响应报文
DNS响应报文
该响应报文使用运输层的UDP协议封装成UDP报文。本例中我们将其内容抽象的表示成文字。然后将其源端口设置成发送来的端口目的端口设置为发送来的源端口

  1. 接收方将UDP用户响应数据报封装在IP数据报中发送给发送方。

用户响应数据报封装在IP数据报中发送给发送方

用户在获得响应报文后,从中解封出用户数据报。根据用户数据报的目的端口,可以知道其传输给DNS进程。


此时会将数据载荷,也就是DNS响应报文交给DNS进程进行处理,DNS进程将其响应报文进行解析,就可知道自己之前所请求的Web服务器的域名,此时就可以开始进行访问域名。

  1. 知道域名对应的IP地址后,可以开始构建HTTP请求,并发送该请求
    构建TCP请求报文

在此例中,将HTTP请求内容抽象为文字,HTTP请求报文的构建需要TCP协议构建TCP首部,在首部中选择一个空闲的短暂端口作为源端口,此时该端口代表TCP应用进程。目的端口选择80,这是HTTP协议所占的常用端口


将TCP报文段封装在IP数据报中,并进行发送

发送HTTP请求报文

HTTP请求报文通过以太网传输到对应Web服务器中,在接收到报文后会对其进行解析,在知道其端口为80后,会将数据载荷部分传输给本服务器中的HTTP服务器端进程进行解析。
HTTP解析内容
解析到内容后按照其要求查找首页内容。


查找到后会给给用户PC发送HTTP响应报文。
构建HTTP响应报文

响应报文内容用抽象文字来表示,此时构建的源端口和目的端口刚好和发送的端口含义相反,原因与上面查询DNS服务过程相同。


构建完后会发送响应报文回用户PC。

  1. Web服务器发送响应报文回用户PC

在这里插入图片描述

用户PC接收到报文后进行解封,解封后发现目的端口是49152,也就是用户PC内的HTTP进程。


因此将数据载荷(HTTP报文)传输给HTTP进程进行处理。


HTTP进程解析到其内同后,在网页浏览器中进行展示。
展示数据

至此,一次网页请求结束。

5.3 UDP和TCP的对比

  • 用户数据报协议UDP(User Datagram Protocol)传输控制协议TCP(Transmission Control Protocol)

  • UDP和TCP是TCP/IP体系结构运输层中两个重要协议,其使用频率仅次于网际层的IP协议
    各层结构协议举例

  • 运输层采用面向连接的 TCP 协议时,尽管下面的网络是不可靠的(只提供尽最大努力服务),但TCP协议就相当于在逻辑上建立了一条通信信道,该信道是全双工的可靠信道

  • 当运输层采用无连接的 UDP 协议时,这种逻辑通信信道是一条不可靠信道

接下来,我们从以下几个方面对比UDP和TCP:

  • 以下的连接逻辑上连接不是物理上的连接。
  1. 在连接方式上:
    连接方式

UDP是无连接的通信方式


TCP是通过著名的**“三次握手”建立连接,“四次挥手”释放连接**。

  1. 在传播方式上:
    传播方式上的区别

UDP由于不建立连接,支持多播和广播


TCP由于每次通信需要建立基于TCP连接的可靠信道,且每次只能建立一条连接,因此只支持单播

  1. 在报文传输处理上:
    报文传输处理上

UDP协议中,对于应用层传输下来的报文不进行处理,保留报文的边界。在给报文加上UDP首部,进行发送。UDP接收方首部接收到UDP数据后,去除其首部,交付给应用层。


可以看出,UDP是针对报文为单位进行处理的,也就是UDP是面向应用报文的


在TCP协议中比较复杂:
在TCP发送方:

TCP协议会把应用进程交付下来的数据块(报文)看作是一连串无结构的字节流(TCP并不知道这些子节含义),将他们编号,并存储在自己的发送缓存中,TCP再根据发送策略,提取一定量的字节,加上TCP首部,构建成TCP报文进行发送。


对于接收方,同时进行两件事:
从所接受到的TCP报文段中,取出数据载荷部分并存储在接收缓存中,同时将接收缓存中的一些字节交付给应用进程


有两个点值得注意:

  1. TCP协议保证接收方收到的字节流和发送方应用进程发出的字节流完全一样
  2. TCP不保证接收方应用进程所收到的数据块与发送方发送的数据块,具有对应大小的关系,例如,发送方应用进程交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块,就把收到的字节流交付给了上层的应用进程。但。就是不会全部将数据交付给上层。


    因此接收方的TCP应用进程必须有能力识别收到的字节流,把它还原成有意义的应用层数据


    可以看出,TCP对报文的处理是以子节为单位的,也就是TCP是面向字节流的,这正是TCP实现可靠传输、流量控制、以及拥塞控制的基础
  • 图中只画了一个方向的数据流,在实际网络中,基于TCP连接的两端,可以同时进行TCP报文段的发送和接收,也就是全双工通信
  1. 在给上层提供的服务上:
    在这里插入图片描述

UDP提供的是不可靠服务
对于发送的UDP数据报,接收方在检测到其误码后直接丢弃不做其他操作。对于发送方发送过程中出现分组丢失,也不做处理。因此其传输数据是不一定能使接收方全部收到数据,因此是不可靠服务


TCP提供的是可靠服务
由于TCP字传输过程中需要建立连接,通过建立的可靠信道进行传输,因此不会出现传输差错,也就是误码、丢失、乱序、重复。因此可以保证发送端发送什么,接收端接收到什么,是可靠传输

  1. 协议首部的对比:

协议首部对比

由于UDP不提供可靠传输的服务,因此其首部只需要在网际层的基础上添加区分端口的子节,其首部比较简单。


在TCP中,需要提供可靠传输、流量控制、拥塞控制等服务,首部比较复杂,字段比较多。

TCP和UDP的对比总结:
对比总结

TCP的流量控制

  • 对于数据传输中,我们希望传输的越快越好,但是若传输过快会导致接收方不够时间接收数据,造成数据丢失。
  • 流量控制就是为了让发送方速率不要太快,要让接收方来的及接收。
  • 利用滑动窗口机制可以很方便的在TCP连接数实现对发送方的流量控制

例如:

A与B建立连接

A与B建立连接,建立完后约定好一个数据传输窗口,例如400:
400的数据窗口
此后,双方传输数据就会以此约束的窗口大小进行。

一次流量控制的例子(以上面400子节为窗口):

流量控制发送第一步

A主机根据窗口长度,向B主机分三次发送了300子节的数据,但是201-300子节数据报丢失,此时发送方还不知道丢失,只知道传输了300子节,还能传输100子节。


此时接收方根据收到的数据,进行累计确认,发送确认信号,此信号的参数含义为:

ACK = 1:这是一个TCP确认字段
ack = 201 :201编号以前的数据全部确认收到
rwnd = 300 : 将接收窗口大小调整为300
(这是第一次流量控制)

流量控制示例2

在A收到确认ACK报文后,根据报文内容,将窗口进行滑动,此时由于前200子节已确认,因此将其从缓存中删除。同时根据报文内容的窗口调整调整为300大小。


然后继续发送数据,直到无法发送窗口已满。


此时由于201-300分组丢失超过重传计数器设置时间,对开始重传201-300分组。


接收方在收到501号所有分组后,发送新的ACK确认报文,报文中将窗口设置为100大小。
(这是第二次流量控制)
流量控制示例3
在接收方接收到ACK报文后,对前500子节数据在缓存中删除,并将窗口调整为100,然后调整滑动窗口位置,开始新的传输。


传输窗口数据后不再传输数据。等待ACK确认信号。


此时接收方接收到数据后再次发送ACK报文,将窗口大小设置为0。
(这是第三次流量控制)

此时由于窗口为零,不再发送数据。此时请考虑一种情况:

调整为零后情况

在缓存不足,接收方窗口调整为0后,过了一段时间便有了新的空间,此时发送一个新的调整窗口报文,但是此时报文传输丢失!无法到达发送方。


此时就会出现发送方等待接收方有缓存空间,接收方等待发送方发送数据的死锁情况

  • 为了解决这个问题,TCP为每一个连接设有一个持续计时器
    -持续计时器

在连接的一方接收到对方的零窗口通知后一段时间后,超时计时器到时,就会发送一个1子节的零窗口发送报文,在接收方接收到该信号后,就会通告自己的窗口大小


当知道窗口可以传输数据后,就会开始通信。

  • 上图如果零窗口探测报文在发送过程中如果丢失,还是能打破死锁局面

  • 因为零窗口探测报文段也有重传计时器,重传计时器超时后,零窗口探测报文段会被重传

值得注意的是:

TCP中规定不论接收方有没有空间,都必须接收发送方的3种报文:
零窗口检测报文段、确认报文段、携带有紧急数据的报文段。

流量控制注意事项

5.5 TCP拥塞控制

  • 拥塞指的是某段时间内,若对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏。
  • 在计算机网络种的资源包括链路容量(带宽)、交换节点种的缓存和处理机等。
  • 若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降
  • 可以将拥塞形象的理解为堵车

拥塞情况

在图中,绿色指的是理想情况下不发生拥塞的情况,此时吞吐量与输入负载相等。当网络资源数被全部利用时,吞吐量不再增长。


红色线指的是出现拥塞不进行处理,会导致吞吐量下降,知道吞吐量为零,产生死锁现象。


蓝色线是** **,在出现拥塞后采用拥塞控制措施,使吞吐量保持在一定水平。

接下来我们学习拥塞控制的4种算法

为了介绍四种拥塞控制算法的基本原理,假定以下条件:
拥塞算法假定条件
先了解拥塞算法中的基本思路

  1. 发送方维护一个叫做拥塞窗口cwnd的状态变量,其值取决于网络的拥塞程度,并且动态表换

拥塞窗口的维护原则:只要没有网络出现拥塞,拥塞窗口就再增大一些,只要网络出现拥塞,拥塞窗口就减少一些。


判断网络拥塞的依据:没有按时收到应到达的确认报文(发生超时重传

  1. 发送方将拥塞窗口作为发送窗口swnd,即:swnd = cwnd
  2. 维护一个慢开始门限ssthresh状态便变量,其维护原则为:
    在这里插入图片描述

慢开始算法

  • 慢开始算法是用来确定网络的负载能力或拥塞程度
  • 算法是实现是由小到大逐渐增大(以倍数增长)拥塞窗口数值
    以一次数据报文传输过程学习慢开始算法:
  • 慢开始指的是一开始网络注入的报文段少,并不是指拥塞窗口cwnd的增长速度慢。

为了更清楚显示出拥塞控制过程,建立以下坐标系:
坐标系

其中横坐标为传输轮次,也就是完整发送一个拥塞窗口数据并且收到确认报文的时间(可以理解为往返时间)。


纵坐标为拥塞窗口,并且根据不同情况会设置一个慢开始门限。

进行第一轮数据通信:
在这里插入图片描述

进行第一轮数据通信时前,发送方会将初始拥塞窗口设为1,并且设置一个ssthresh(慢开始传送位),然后开始传送数据,在收到确认报文后
将拥塞窗口设置新值
拥塞窗口设置为原来的两倍

此时,座标系情况如下:
座标系情况1
进行第二次发送:
第二次发送

第二次发送顺利进行,成功接收到确认报文后,将拥塞窗口增大到4.

此时坐标轴情况:
坐标轴情况2

进行第三轮发送:

第三轮发送

第三次发送顺利进行,成功接收到确认报文后,将拥塞窗口增大到8.

进行第四轮发送:
第四轮发送

第四次发送顺利进行,成功接收到确认报文后,将拥塞窗口增大到16.
坐标轴情况3

此时可以看出,**拥塞窗口已达到慢开始门限SSTHRESH,**此时,慢开始算法使用阶段结束开始拥塞避免算法阶段

拥塞避免算法

  • 拥塞避免算法让拥塞窗口 cwnd 缓慢地增大(每伦窗口大小+1),避免出现拥塞。
  • 在拥塞避免阶段,具有 “加法增大” (Additive Increase) 的特点
  • 拥塞避免算法并不能完全避免拥塞,只是在拥塞避免阶段将容易拥护的窗口控制为按线性规律增长,是网络比较不容易出现拥塞

接上面的例子:

进行第六轮传输:
第六轮传输

此时不再使用慢开始算法,采用拥塞避免算法,每个轮次只给拥塞窗口+1.

此时坐标轴情况如下:

坐标轴情况5
第七轮传输:
在这里插入图片描述

传输成功后,给拥塞窗口+1.

循环重复此传输过程,若出现以下情况:
出现报文段丢失情况
重传计时器超时

出现重传计时器超时后,判断网络很可能出现了拥塞,进行以下工作:

  1. 将ssthresh值更新为拥塞时cwnd值的一半
  2. 将cwnd值减少为1,重新开始直行慢开始算法

对于以上两个算法的完整示意图:
两个算法的完整示意图
有一种情况:
错误设置窗口情况
因此提出了快重传算法和快恢复算法。

快重传算法

  • 快重传指的是在出现分组错误后,发送方尽快重传数据,而不是等待超时计时器超时再重传。

快重传算法三个原则:

  1. 要求接收方不要等等自己发送数据时才进行捎带确认,而是要立即发送确认
  2. 即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认
  3. 发送方一旦收到了3个连续的重复确认,就立即将相应的报文段立即重传,不用等到超时计时器超时后再重传。
  • 对于个别丢失的报文段,发送方不会出现超时重传,也就不会误认为出现了拥塞(这会使拥塞窗口设置为1),该算法可以使整个网络吞吐量提高约20%。

例如:
快重传算法

在快重传算法中,发送方会在接收到确认分组前就发送下一个分组(前提是在拥塞窗口大小内),对于丢失的分组,会在收到3个分组后发送3个重复确认丢失分组序号。


接收方收到3个重复分组序号后便开始重传,而不是等待超时计时器到时。


这样子也不会误以为出现了拥塞。

快恢复算法

  • 发送方在收到3个重复确认后,就知道现在只是丢失了个别的报文段。于是不开始启动慢开始算法,转而执行快恢复算法
  • 快恢复算法是发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半,并开始直星拥塞避免算法。
  • 有部分快恢复实现是把快回复开始时的拥塞窗口swnd值再增大一些,即等于SSTHRESH + 3,理由如下:

设置为SSTHRESH + 3理由

四个算法再传输过程中的使用顺序图:
算法使用顺序图

一开始使用慢开始算法拥塞窗口开始指数规律增大到设定的ssthres值后执行拥塞避免算法。


拥塞避免算法将拥塞窗口以1为单位线性增大,直到出现分组丢失,重传计时器时间到后,cwnd设置为1,ssthresh值设置为发生拥塞的窗口值大小一半,并重新开始执行慢开始算法


在发送方收到3个重复确认时及逆行快重传和快恢复算法,将ssthresh的值更新为当前拥塞窗口值得一半,更新cwnd值为ssthresh值

5.6 TCP超时重传时间的选择

  • TCP超时重传时间的选择是TCP最复杂的问题之一

RTTO过短

若RTTO超时重传时间过短会导致不必要的重传,使网络负荷增大。

RTO过长

RTO过长会导致网络的空闲时间增大,降低了传输效率。

RTT的适合时间

因此,**RTTO的设置应该略大于RTT,**但是此时又会出现一个问题,由于网络传输环境的不同,导致接下来的RTT是不确定的,如此应该如何去去认定RTO?

  • 因此不能直接用某次测量得到的RTT样本值来计算超时重传时间RTO
  • 要利用每次的量得到的RTT样本,计算加权平均往返时间RTTs(又称为平滑的往返时间)

关于RTTs的计算:
RTTs的计算
在RFC6298建议使用下式计算超时重传时间RTO:
RFC6298建议下的RTO计算
由于超时重传机制的存在,有时接收到确认报文不能确定其是首次发送的确认报文还是重传后的确认报文,因此往返时间RTT的测量也是比较复杂:
RTT测量复杂
针对以上问题,有以下解决方式:
Karn解决算法
下面我们看一个计算RTO的例子:
计算RTO例子

关于RTO的小结如下:
RTO小结

5.7 TCP可靠传输的实现

  • TCP基于以子节为单位的滑动窗口来实现可靠传输

例如:
TCP可靠传输的实现

在要传递的字节流中,可以大致分为几个区域:


发送窗口后数据(图中的左边):这些数据已经成功发送出去并且已经收到确认信号,因此这部分数据可以从缓存中删除


发送窗口中数据(图中的蓝色部分):这部分数据正处于发送窗口中,此时数据有两种情况,已发送正在等待确认或者未发送出去,对于已发送的数据要存在发送缓存中。


发送窗口前数据(图中的右半部分):这部分数据不允许发送。


根据发送的具体情况,发送窗口的后延移动情况有两种:


不动:没有收到新的确认信息。


前移:收到了新的确认信息。


根据发送的具体情况,前,发送窗口的前延移动情况有三种


不间断向前移动:收到了新的确认分组


不动没有收到新的确认分组并且对方的通知窗口信号大小不变收到新的确认但对方通知的端口缩小个数等于后延移动的位数,使得发送窗口前沿正好不动


向后收缩:对方通知的窗口缩小了,但是这种情况容易造成错误,是TCP协议不愿看到的情况

由于发送窗口中的字节可能是已经发送的或者未发送的,就出现了一个问题,我们应该如何描述发送窗口中数据的状态
描述发送窗口状态的方法

可以采用三个指针来定位不同状态区域

在接收方中也有跟发送方相同的字节序列情况:
接收方字节状态

其字节序列也可以分为三个部分,跟发送方一致,不过多赘述。

接受方收到未按序到达的数据

若接收方收到未按序到达的数据,如本例收到32-33编号字节数据,由于TCP的确认方式是只能发送按序收到的最高序号确认,因此发送一个ack = 31的确认信号,也就是表示现在需要发送31号数据。


发送方收到ack = 31报文后,知道31号数据未按序到达,但是根据上面所学的知识,只有第3次接收到同一个ack信号才会进行重传,此时不做处理,继续发送往下的数据

成功接收到31序号

此时若成功接收到31号数据,此时31-33号数据按序到达,此时接收方会择机将数据交给应用层,并且将窗口向后滑动3字节,同时发送确认报文

发送确认报文以及同时有数据来到

在接收方发送的确认报文被发送方收到后,会将发送窗口向后滑动若干字节(此处为3字节)发送方此时会将31.32.33字节数据从缓存中删除


此时若发送方又发送了3个未按序到达的数据。此时接收方接受数据后不做处理。

发送方继续发送剩余的数据

若发送方发送完全部的发送窗口数据,此时不能再发送数据。


此时若迟迟等不到接收方确认信号,重传计时器超时,此时会重新发送发送窗口内已发送的数据,并重启重传计时器。

关于可靠传输实现的注意事项:
可靠传输实现的注意事项

5.8 TCP的运输链接管理

TCP连接的建立(三握)

  • TCP是面向连接的协议,它基于运输连接来传送TCP报文段
  • TCP运输连接的建立和释放时每一次面向连接的通信中必不可少的过程
  • TCP运输连接建立有以下三个阶段:
    TCP运输连接建立有三个阶段:

这三个阶段就是我们听说最久的:
三次挥手建立连接、建立连接后进行数据传输、四次挥手释放TCP连接

  • TCP的运输连接管理就是使用运输连接的建立和释放都能正常的进行

TCP的连接建立要解决以下三个问题:

  1. 使TCP双方都能确知对方的存在
  2. 使TCP双方能够协商一些参数(如窗口最大值、是否使用窗口扩大选项和时间戳选项和服务质量等等)
  3. 使TCP双方能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配

使用三报文握手建立连接的具体过程:

三次握手最开始双方状态

在三报文握手过程中,有两个角色客户端发送握手连接请求,服务器等待接收请求。


在最开始:双方都是处于关闭状态,此时双方的TCP进程都是关闭的。

此时,服务器在连接之前要进行准备
TCP服务器进行准备

准备过程中,服务器创建传输控制块,在块中有TCP连接表等一些TCP连接的重要信息。创建后便开始监听,准备接收来自客户端的连接请求。

值得注意的是:

TCP服务器进程是被动等待来自TCP客户进程的连接请求。而不是主动发起,因此称为被动打开连接。

与服务器类似,客户端进程也需要进行准备:

客户端进程进行准备

其准备过程只有建立传输数据块。

准备完毕后开始”握手“:

第一次发送握手报文:

第一次发送握手报文

在打算建立TCP连接时,客户端向TCP服务器进程发送TCP连接请求报文段,并进入同步已发送状态


TCP连接请求报文段首部中,有两个关键数据:

  1. 同步位SYN被设置为1表明这是一个TCP连接请求报文段

  2. 序号字段seq:被设置了一个初始值x,作为TCP客户端进程所选择的初始序号

请注意:TCP规定SYN被设置为1的报文段不能携带数据,但要消耗掉一个序号

服务器收到信号后,发送第二次握手报文:

服务器收到信号后

TCP服务器进程收到客户端发送的TCP连接请求报文段后,如果同意建立连接,则向TCP客户进程发送TCP连接请求确认报文段,并进入同步已接收状态


TCP连接请求确认报文段首部中有几个关键数据位:


同步位SYN和确认为ACK:都设置为1,表明这是一个TCP连接请求确认报文段。


序号字段seq:设置了一个初始值y,作为TCP服务器进程所选择的初始序号


确认号字段ack:值被设置成了x+1,这是对TCP客户进程所选择的初始序号(seq)的确认


值得注意的是:这个报文段也不能携带数据,因为它是SYN被设置为1的报文段,但同样要消耗掉一个序号

发送方接收到确认报文后,开始第三次握手:

发送方进行第三次握手

TCP客户进程收到TCP连接请求确认报文段后,还要向TCP服务器进程发送一个普通的TCP确认报文段,并进入连接已连接状态


普通的TCP确认报文段首部中有以下重点数据位:


确认位ACK:设置为1,由于没有SYN同步字段,表明这是一个普通的TCP确认报文段,表示已确认收到建立连接报文。


序号字段seq:设置为x+1,因为TCP客户进程发送的第一个TCP报文段的序号为x,所以TCP客户进程发送的第二个报文段的序号为x+1(SYN字段报文需要消耗一个序号)


确认号字段ack:设置为y+1,这是对TCP服务器进程所选择的初始序号的确认
值得注意的是:TCP规定普通的TCP确认报文段(只有ACK没有SYN)可以携带数据,但如果不携带数据,则不消耗序号

三次握手完毕

三次握手完毕后,服务器也进入连接已建立状态,此时双方连接已建立,可以开始进行数据传输。

这里有一个问题:

为什么TCP客户端进行最后还要发送一个普通的TCP确认报文段呢?是否多余?

答案是否定的。

  • 三次握手建立连接是为了防止已经失效的连接请求报文段突然又传到服务端,产生错误

例如,下面采用两次握手就建立连接:

两次握手建立连接示例

客户端发出去了第一个连接请求报文并没有丢失,但是由于某种原因造成了较长时间的迟到现象


此时发送端重新开始发送请求连接报文,并且通过两次握手成功建立连接,没有进行请求序号的验证


在传输完数据之后,通过四次挥手释放连接。此时双方处于关闭连接状态


但是此时,已经迟到多时的请求报文到达了服务器,本来这是一个早已失效的报文段,但是服务器收到此失效的报文之后,会误认为是客户端再次发出的一个新的连接请求


于是服务器就向客户端又发出确认报文,表示同意建立连接。此时服务器处于连接状态,而客户端由于处于关闭状态,不会接收该确认报文。


如果不采用“三次握手”服务端接收到客户端发出的请求报文就会认为要请求建立新的连接,并且进入连接状态,但是客户端此时可能并没有发出建立连接的请求,该报文是由于某种情况迟到的请求,因此不会去向B端发送数据,服务端没有收到数据就会一直等待


这样子会造成服务端白白浪费掉很多资源。

综上所诉,三次握手并不多余,这是为了防止已失效的连接请求报文段突然又传送到了TCP服务器,因而导致错误。

总结:

三次握手总结

TCP连接的建立释放(四挥)

  • TC通过四报文挥手来释放连接

以下图解说明:

数据建立主动释放

在双方连接已建立后,此时需要客户端主动发出关闭信号

第一次挥手:
第一次挥手

TCP客户进程发送TCP连接释放报文段,并进入终止等待1状态


TCP连接释放报文段首部中有以下关键数据位:


终止位FIN和确认位ACK:值都被设置为1表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认


序号seq字段:值设置为u,u等于TCP客户进程之前已传送过的数据的最后一个字节的序号加1,用来表示发送过程中的最后一个字节序号为u。


确认号ack字段:值设置为vv等于服务器进程之前发送的数据中最后一个字节的序号加1,也就是确认收到已经收到的服务器发送的数据

  • 请注意:TCP规定终止位FIN等于1的报文段即使不携带数据,也要消耗掉一个序号

第二次挥手:
第二次挥手

接收方再接收到连接释放报文后,会发送一个普通的TCP确认报文段并且进入关闭等待状态


普通的TCP确认报文段首部中有以下关键数据位:
确认位ACK:值被设置为1,表明这是一个普通的TCP确认报文段。


序号seq值设置为v,v等于TCP服务器进程之前已传送过的数据的最后一个字节的序号加1与之前收到的TCP连接释放报文段中的确认号ack值匹配


确认号ack字段:值为u+1,这是对TCP连接释放报文段的确认,也就是为发送方连接释放报文中的seq的值+1.

第二次挥手后服务器状态

在进行第二次挥手后,会产生以下过程:


TCP服务器进程通知高层应用进程TCP客户进程要断开与自己的TCP连接,此时的TCP连接进入半关闭状态


所谓半关闭状态可以认为,此时客户端与服务器的连接不再传输数据,也就是客户端没有数据在发生。而此时服务器若有剩余数据要发送会继续发送。客户端到服务器这一信道关闭了,而服务器到客户端这一半没有关闭,因此称为半关闭状态


这个半关闭状态可能会持续一段时间,直到发送方没有数据进行发送。

在以上等待过程中,客户端会进入终止等待2状态
终止等待2状态
此时当服务器没有数据要传输后。进行第三次挥手:
第三次挥手

此时TCP服务器进程会发送TCP连接释放报文段并进入最后确认状态。


在该报文段中有以下关键数据段:


终止位FIN和确认位ACK:值都被设置为1,表明这是一个TCP连接释放报文段,同时也对之前收到的报文段进行确认


序号seq:值为w,因为在半关闭状态下,TCP服务器进程可能又发送一段数据,因此w就是该段数据最后的序号


确认号ack:值为u+1,这是对之前收到的TCP连接释放报文段的重复确认,因此值与发送方第一次挥手发送的seq值+1

TCP客户进程收到TCP连接释放报文段后开始第四次挥手:第四次挥手

此时针对第三次挥手的报文段发送普通的TCP确认报文段,之后进入时间等待状态


该报文段首部中有以下关键数据位:


确认位ACK:值被设置为1,表明这是一个普通的TCP确认报文段


序号seq字段:值设置为u+1,用来表示最后一个发送的字节序号,但是为何没有发送数据,而此时值要设置为u+1(对比第一次挥手数据)?,因为TCP客户进程之前发送的TCP连接释放报文段(带有FIN)虽然不携带数据,但要消耗掉一个序号


确认号ack:值设置为w+1,这是对所收到的TCP连接释放报文段的确认

此时,TCP服务器进程收到该报文段后就进入关闭状态,而TCP客户进程还要经过2MSL后才能进入关闭状态:

可独断经过2MSL后才能进入关闭状态

MSL具体的值可以根据TCP协议的不同实现进行设置。

此时就会出现一个问题:

  • 为什么不发送报文段后直接关闭,而是要等待2MSL个时间后才关闭?是否有必要?

答案是有必要

考虑以下情况:

不等待2MSL的情况

若客户端发送完最后一次报文后,也就是第四次挥手后就直接进入关闭状态,此时若第四次挥手报文丢失,会导致服务器的超时重传


此时客户端又已经关闭,导致不接受该报文,因此服务器会一直不断重传,并一直处于最后确认状态无法进入关闭状态


因此,有以下结论
客户端进入时间等待状态以及处于该状态2MSL时长,可以确保TCP服务器进程可以收到最后一个TCP确认报文段而进入关闭状态


TCP客户进程在发送完最后一个TCP确认报文段后,在经过2MSL时长,就可以使本次连接持续时间内所产生的所有报文段都从网络中消失,这样就可以使下一个新的TCP连接中,不会出现旧连接中的报文段

若出现这样一种情况:

TCP双方已经建立了连接,但是传输过程中TCP客户进程所在的主机出现了故障,此时TCP服务器进程以后就不能再收到TCP客户进程发来的数据,这时服务器进程会一直处于等待状态。

为了使TCP服务器进程不要再白白等待下去出现了TCP保活计时器:

TCP保活计时器:
保活计时器

5.9 TCP报文的首部格式:

  • 为了实现可靠传输,TCP采用了面向字节流的方式。
  • 在发送数据时,从发送缓存中取出一部分或者全部字节,并给其添加一个首部使之称为TCP报文段。
    TCO报文段
    我们对TCP首部报文段进行了解:
    TCP首部

TCP首部和IP地址的首部类似,都由固定部分和扩展部分构成

源端口和目的端口字段:
源端口和目的端口字段
例如:
源端口和目的端口字段

在其发送的首部中就会有地址号和目的端口号,关于域名访问过程的详细可以看:域名访问简单过程解析

序号、确认号、ACK字段:
序号

图中例子序号为166,就是从166开始。

确认号

也就是四次挥手中的SEQ.

ACK
以上三个字段的使用例子:
三个字段例子

数据偏移字段:数据偏移字段
例如:
数据偏移例子

数据偏移二进制数的十进制表示 * 4 = 首部长度

保留、窗口、校验和字段:
保留、窗口
校验和
与连接管理相关的字段:

同步标志位
终止标志位
复位标志位字段
推送标志位字段
紧急标志位URG紧急指针
选项和填充字段:

选项字段
填充字段


如果觉得文章写的还不错,麻烦点个赞支持一下,欢迎评论,互相交流学习。

猜你喜欢

转载自blog.csdn.net/Nimrod__/article/details/113664991