TCP/IP(五)运输层

目录

一、运输层概述

二、用户数据报协议UDP

三、传输控制协议TCP

         3.1 TCP概述
         3.2 TCP连接过程

四、可靠传输

五、流量控制

六、拥塞控制

 
 
 
 

一、运输层概述

 
运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两台主机使用网络的核心部分的功能进行通信的时候,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时只用到下三层的功能。

从运输层的角度看,通信的真正端点不是主机而是主机中的进程。也就是说,端到端的通信是应用进程之间的通信。

传输层的功能: 提供应用进程间的逻辑通信。(网络层提供主机之间的逻辑通信)

在这里插入图片描述

由这里可以看出,网络层为主机之间提供逻辑通信,而运输层为应用进程之间提供逻辑通信。逻辑通信的意思是,好像是这样进行通信,但事实上并非这样通信。中间要经过各种处理。

二、用户数据报协议UDP

UDP只在IP数据报服务之上增加了复用分用和差错检测功能

在这里插入图片描述

UDP 的特点:

1、传送数据前无需建立连接,数据到达后无需确认。减小开销和发送数据之前的时延

2、不保证可靠交付。(交由应用层保证可靠交付)

3、面向报文,适合一次性传输少量数据的网络应用,报文头部短,传输开销小。

4、UDP无拥塞控制,适合实时应用

5、UDP首部开销小,8B。TCP20B

应用层给UDP多长的报文,UDP只加上首部发送。即一次发送一个完整报文。

UDP报文段

UDP数据报的组成
在这里插入图片描述

在这里插入图片描述

UDP校验

UDP校验只提供差错检测,在计算校验和时,要在UDP用户数据报之前临时加上12B的伪首部。包括源IP地址字段、目的IP地址字段、全0字段、协议字段(封装UDP报文的IP数据报首部协议字段为17)、UDP长度字段(UDP首部8B+数据部分长度不包括伪首部)。伪首部只用于计算和验证校验和,既不向下传送,也不向上递交。

发送端:

1、填上伪首部。
.
2、校验的时候如UDP数据报数据部分的长度不是偶数字节,则需要填入一个全0字节,保证UDP数据报是4B整数倍。但此字节和伪首部一样不发送。
.
3、伪首部+首部+数据部分采用二进制反码求和
.
4、将和进行求反码,再填入检验和字段。
.
4、去掉伪首部发送。

接收端:

1、填上伪首部
.
2、伪首部+首部+数据部分采用二进制反码求和
.
3、和全为1则无差错。否则校验出UDP数据报是错误的,可以丢弃或者交付上层,但需要附上错误报告

通过伪首部,不仅可以检查源端口号、目的端口号和UDP用户数据报的数据部分,还可以检查IP数据报的源IP地址和目的地址。

在这里插入图片描述

虽然该检验方法检错能力不强,但是简单,处理快。
 

三、传输控制协议TCP

 

3.1 TCP 概述

上面提到UDP传送数据之前不需要先建立连接,远地主机的运输层在收到UDP报文后,不需要给出任何确认。不需要提供可靠交付。

与UDP不同,TCP则需要提供面向连接的服务,在传送数据之前必须先建立连接,传送数据之后必须取消连接。TCP不提供广播或多播服务。由于 TCP 要提供可靠的、面向连接的运输服务,因此不可避免的增加了许多的开销。如确认、流量控制及连接管理。

TCP的主要特点:

1、面向连接(虚连接),不提供广播或多播服务
.
2、每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。
.
3、TCP提供可靠交付的服务,无差错、不丢失、不重复、按序到达。
.
4、提供全双工通信。两个端点都设置发送缓存(准备发送的数据和已发送但未确认的数据)和接受缓存(按序到达但未被应用程序读取的数据和不要序到达的数据)
报文段头部长,传输开销大
.
5、面向字节流。TCP把应用程序交下来的数据看成无结构的字节流。

TCP报文段

在这里插入图片描述

序号:TCP连接中传送的字节流中的每一个字节都是按顺序编号,该字段表示本报文段所发送的数据的第一个字节的序号。

确认号期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,则证明序号N-1为止的所有数据已经确认收到。

数据偏移(首部长度):TCP报文段的数据起始距离TCP报文段的起始处有多远,以4B为单位。

紧急位URG:URG=1,表明此报文段有紧急数据,高优先级的数据,需要尽快传送,不需要在缓存里排队,搭配紧急指针字段使用。优先传送。

确认位ACK:ACK=1时确认号有效,建立连接后所有传送的报文段都必须将ACK置1。

推送位PSH:PSH=1时,接收方尽快交付接收应用进程,不再等待缓存填满再向上交付。优先交付。

复位RST:RST=1,表明TCP连接中出现严重出错,必须释放连接,然后重新建立连接。

同步位SYN:SYN=1,表明这是一个连接请求/连接接受报文。

终止FIN:FIN=1,释放连接。

窗口:指发送本报文段的一方的接收窗口,即允许对方发送的数据量。

检验和:检验首部+数据,检验时加上12B伪首部,协议字段为6。

紧急指针:URG=1时有意义,指本报文段中紧急数据的字节数

选项:最大报文段长度MSS(每一个TCP报文段中的数据字段的最大长度,默认536B)、窗口扩大(3B)、时间戳(10B(时间戳值字段4B和时间戳回送回答字段4B))、选择确认(SACK)…
填充

在TCP报文段的首部中只有端口号而没有IP地址。当TCP将其报文段交给IP层时,IP如何知道目的IP地址的?

在这里插入图片描述

3.2 TCP 连接过程

TCP连接过程中我们主要用到三个标识位:

SYN:SYN= 1 表示这是一个连接请求或连接接受报文。在建立连接时用来进行同步序号(个人理解是,在建立连接的时候,提醒对方记录本方的起始序号)。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若是同意建立连接,则应响应的报文段中使SYN=1、ACK=1。因此SYN=1表示该报文是一个连接请求报文或者是一个连接请求接收报文。

ACK:确认号只有在该位设置为1的时候才生效,当该位为0是表示确认号无效。TCP规定,在TCP连接建立后所有传送的数据报文段ACK都必须设置为1。

FIN:当 FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。

此外我们还需要用到序号和确认号:

序号:占4个字节,它的范围在0-2^32-1,序号随着通信的进行不断的递增,当达到最大值的时候重新回到0在开始递增。TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按照顺序编号。整个要传送的字节流的起始号必须在连接建立时设置。首部中的序列号字段指的是本报文段所发送的数据的第一个字节的序号。例如,一个报文序号是301,而携带的数据共有100字节。则表示本次报文中的序号是301,下一个报文的序号是401.重复一下,每一个报文的序号是该报文包含的字节中第一个字节的编号。

确认号:占4个字节,确认号,是对下一个想要接受的字节的期望,这里隐式确认了对上一个数据包的成功接收。如上例,在成功接收了序号为301的数据包,想要接收下一个数据包因为上个数据包包含100字节,所以此时的确认号应该是401,表示希望接收下一个序号是401的数据包。

三次握手过程

在这里插入图片描述

1、过程描述:

首先由Client发出请求连接即 SYN=1 ACK=0 (请看头字段的介绍),TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x。

然后 Server 进行回复确认,即 SYN=1 ACK=1 seq=y,ack=x+1。

再然后 Client 再进行一次确认,但不用SYN 了,这时即为 ACK=1, seq=x+1,ack=y+1。

2、为什么要进行三次握手(两次确认):

为什么A还要发送一侧确认呢?这主要是为了防止已失效的连接请求报文突然又传送到了B,因而产生错误。

所谓“已失效的连接请求报文段”是这样产生的。考虑一种正常情况。A发出连接请求,但因连接请求丢失而未收到确认。于是A再次重传一次连接请求。后来收到了确认建立了连接。数据传输完毕后,就释放了连接。A供发送了两个连接请求的报文段,其中第一个丢失,第二个到达了B。没有“已失效的连接请求报文段”。

现假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络节点长时间滞留了,以致延误到连接释放以后的某个时间才到B。本来这是一个已失效的报文段。但是B收到此失效的连接请求报文段后,就误认为是A有发出一次新的连接请求。于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了。

由于现在A并没有发出建立连接的请求,因此不会理睬B的确认,也不会向B发送数据。但B却以为新的运输连接已经建立了,并一直等待A发来数据。B的许多资源就这样拜拜浪费了。

采用三次握手的办法可以防止上述现象的发生。例如在刚才的情况下,A不会向B的确认发出确认。B由于收不到确认,就知道A并没有要求建立连接。

另一种解释:

这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了”。这可视为对“三次握手”目的的另一种解答思路。

3、四次挥手关闭连接

在这里插入图片描述

当客户A 没有东西要发送时就要释放 A 这边的连接,A会发送一个报文(没有数据),其中 FIN 设置为1, 服务器B收到后会给应用程序一个信,这时A那边的连接已经关闭,即A不再发送信息(但仍可接收信息)。 A收到B的确认后进入等待状态,等待B请求释放连接, B数据发送完成后就向A请求连接释放,也是用FIN=1 表示, 并且用 ack = u+1(如图), A收到后回复一个确认信息,并进入 TIME_WAIT 状态, 等待 2MSL(Maximum segment Lifetime) 时间。

|| 为什么要等待呢?

为了防止这种情况:A接到B的释放连接请求后会发送一个确认信息,但是如果这个确认信息丢了,也就是B没有收到确认释放连接,那么B就会重发一个释放连接请求,这时候A还处于TIME_WAIT状态,所以会再次发送一个确认信息。

|| Q2为什么TIME_WAIT 状态还需要等2*MSL秒之后才能返回到CLOSED 状态呢?

A2因为虽然双方都同意关闭连接了,而且握手的4个报文也都发送完毕,按理可以直接回到CLOSED 状态(就好比从SYN_SENT 状态到ESTABLISH 状态那样),但是我们必须假想网络是不可靠的,你无法保证你最后发送的ACK报文一定会被对方收到,就是说对方处于LAST_ACK 状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT 状态的作用就是用来重发可能丢失的ACK报文。

11种状态

在这里插入图片描述

简单解释:

l CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”。

l LISTEN :表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。

l SYN_RCVD :表示服务器接收到了来自客户端请求连接的SYN报文。在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat很难看到这种状态,除非故意写一个监测程序,将三次TCP握手过程中最后一个ACK报文不予发送。当TCP连接处于此状态时,再收到客户端的ACK报文,它就会进入到ESTABLISHED 状态。

l SYN_SENT :这个状态与SYN_RCVD 状态相呼应,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送SYN报文。

l ESTABLISHED :表示TCP连接已经成功建立。

l FIN_WAIT_1 :这个状态得好好解释一下,其实FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET进入到FIN_WAIT_1 状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2 状态。当然在实际的正常情况下,无论对方处于任何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1 状态一般是比较难见到的,而FIN_WAIT_2 状态有时仍可以用netstat看到。

l FIN_WAIT_2 :上面已经解释了这种状态的由来,实际上FIN_WAIT_2状态下的SOCKET表示半连接,即有一方调用close()主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2 状态会导致内核crash。

l TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,但BSD传统实现采用了30秒,Linux可以cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值),然后即可回到CLOSED 可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(这种情况应该就是四次挥手变成三次挥手的那种情况)

l CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接。

l CLOSE_WAIT :表示正在等待关闭。怎么理解呢?当对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当你处于CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。

l LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了

四、可靠传输

TCP 发送的报文段是交给 IP 层的。但是 IP 层只能提供尽最大努力服务,也就是说,TCP 下面的网络的传输是不可靠的传输。因此,TCP 必须采取适当的措施才能使两个运输层之间的通信变得可靠。

TCP实现可靠传输工作的机制:

校验:与UDP校验一样,增加伪首部。

序号:TCP是面向字节的。TCP将所要传送的报文看作是字节组成的数据流,并使每一个字节对应一个序号。在连接建立时,双方要确定初始序号。TCP每次发送的报文段的首部中的序号字段数值表示该报文段的数据部分的第一个字节的序号

确认:TCP的确认是对接收到的数据的最高序号表示确认。接收端返回的确认号是已收到的数据的最高序号加一。因此,确认号表示接收端期望下次收到的数据中的第一个数据字节的序号。

重传:TCP的发送方在重传时间内没有收到确认就重传已发送的报文段。由于TCP的下层是一个互联网环境,IP数据报所选择的路由变化很大,所以运输层的往返时延的方差也很大。为了计算超时计时器的重传时间,TCP采用一种自适应的算法,动态改变重传时间RTTs(加权平均往返时间)。

记录每个报文段发出的时间以及收到相应的确认报文段的时间。时间差就是报文段的往返时间。
.
将各个报文段的往返时间样本加权平均,得到报文段的平均往返时间RTT
.
每测量到一个新的往返时间样本,就按公式重新计算一次平均往返时间。
.
RTT₁=(1-α)(RTT₀)+α(往返时延样本)
.
α越接近1表示RTT的值更新越快,一般推荐α=0.125。计时器的超时重传时间RTO应略大于RTT。

超时重传等待时间结束才重传,使用冗余确认方式,在超时事件发生之前,知道发送方是否丢失报文段(快速重传)

冗余ACK(冗余确认)

每当比期望序号大的失序报文段到达时,发送一个冗余ACK,指明下一个期待字节的序号。

发送方发送1、2、3、4、5报文段 接收方收到1,返回1的确认报文段(确认号ack=2,期待收到下一个报文段2的第一个字节)
.
接收方收到3,返回1的确认报文段(冗余确认报文段,确认号ack=2) 接收方收到4,返回1的确认报文段(冗余确认报文段,确认号ack=2)
.
接收方收到5,返回1的确认报文段(冗余确认报文段,确认号ack=2)
.
发送方收到3个1号报文段的冗余确认报文段⇒认为2号报文段丢失,重传2号报文段。

在使用TCP传送数据时,如果有一个确认报文段丢失了,会不会一定引起对方数据的重传?

是否TCP和UDP都需要计算往返时间RTT?

假定在一个互联网中,所有的链路的传输都不出现差错,所有的结点也都不会发生故障。试问在该情况下TCP的“可靠交付”的功能是否就是多余的?

五、流量控制

流量控制:让发送方的发送速率不要太快,要让接收方来得及接收。

利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。

在通信过程中,接收方根据自己接收缓存的大小,动态的调整发送方的发送窗口大小,即接收窗口rwnd(接收方设置确认报文段的窗口字段来将rwnd通知给发送方)发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值

A向B发送数据,连接建立时,B告诉A:“rwnd=400B”,设每一个报文段100B,报文段序号初始值为1。

在这里插入图片描述

接收窗口为0,当接收应用程序读取收到的数据,接收窗口扩大,发送方不发送数据,导致接收方无法发送确认告发送方接收窗口扩大,双方陷入死锁僵局。

TCP为每一个连接设有一个持续计时器 。只要TCP连接的一方收到对方地零窗口通知,就启动持续计时器。

若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带1B的数据)而对方就在确认这个探测报文段时给出了现在的窗口值。

若窗口仍然是零,则接收到这个报文段的一方就重新设置持续计时器。若窗口不为零,则死锁的僵局就被打破。

可以使用不同的机制控制TCP报文段的发送时机

TCP维持一个变量,等于最大报文段长度MSS。只要缓存中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去。
由发送方的应用进程指明要求发送报文段,即TCP支持的推送(push)操作。
发送方的一个计时器期限到了,这是就把当前已有的缓存数据装入报文段发送出去。

五、拥塞控制

出现拥塞的条件:对资源需求的总和>可用资源

网络中有许多资源同时呈现供应不足⇒网络性能变坏⇒网络吞吐量随输入负荷增大而下降。

拥塞控制:防止过多的数据注入到网络中。

拥塞控制与流量控制的性质对比

拥塞控制所要做的只有一个前提,就是使得网络能够承受现有的网络负荷。
.
拥塞控制是一个全局性的过程,涉及所有的主机、所有的路由器以及与降低网络传输性能有关的所有因素。
.
流量控制往往指在给定的发送端和接收段之间的点对点通信量的控制。 流量控制所要做的就是抑制发送端发送数据的速率,以便接收端来得及接收。
.
拥塞控制很难设计,因为它是一个动态的问题。
.
当前网络正朝着高速化的方向发展,很容易出现缓存不够大而造成分组的丢失。分组的都是是网络发生拥塞的征兆而不是原因。
.
在许多情况下,正是拥塞控制本身成为引起网络性能恶化甚至发生死锁的原因。

拥塞控制分为闭环控制开环控制

  • 开环控制方法就是在设计网络时实现将有关发生拥塞的因素考虑周到,力求网络在工作时不产生拥塞
  • 闭环控制是基于反馈环路的概念,属于闭环控制的有以下措施

     1、检测网络系统以便检测到拥塞在何时、何地发生
     2、将拥塞发生的信息传送到可采取行动的地方
     3、调整网络系统的运行已解决出现的问题。

拥塞控制算法:

假定:

数据单方向传送,另一个方向只传送确认。

发送端的主机在确定发送报文段的速率时,既要根据发接收端的接收能力,又要从全局考虑不使网络发生拥塞。即TCP要求发送端维护接收窗口rwnd和拥塞窗口cwnd

接收窗口:接收方根据受缓存设置的值,并告知给发送方,反映接收方容量。

拥塞窗口:发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络当前容量。

接收方总是有足够大的缓存空间,发送窗口大小取决于拥塞程度。发送窗口=Min{接收窗口rwnd,拥塞窗口cwnd}

在这里插入图片描述

慢开始和拥塞避免

慢开始原理:

  1. 在主机刚刚开始发送报文段时可先设置拥塞窗口cwnd=1,设置为一个最大报文段MSS的数值。

  2. 在每收到一个对新的报文段的确认后,将拥塞窗口加一,既增加一个MSS的数值。

  3. 用该方法逐步增大发送端的拥塞窗口cwnd,可以使分组注入网络的速率更合理。

拥塞避免算法原理:

  • 为防止拥塞窗口cwnd的增长引起网络阻塞,需要一个状态变量,即慢开始门限ssthresh
  • 当cwnd<ssthresh时,使用慢开始算法
  • 当cwnd>ssthresh时,停止使用慢开始算法,改用拥塞避免算法
  • 当cwnd=ssthresh时,既可以使用慢开始算法,也可以使用拥塞避免算法。
  • 其中,拥塞避免算法的做法为,发送端的拥塞窗口cwnd每经过一个往返时延RTT就增加一个MSS的大小,通常表现为按线性规律增长。

无论在慢开始阶段还是拥塞避免阶段,只要发送方判断网络出现拥塞(即未按时收到确认)就把慢开始门限ssthresh设置为出现拥塞时的发送窗口的一半(即ssthresh(慢开始门限):新的ssthresh门限值=½网络拥塞时的拥塞窗口cwnd,但不能小于2)。然后把拥塞窗口cwnd重新设定为1,执行慢开始算法。

可以减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够的时间把队列中积压的分组处理完毕。

在这里插入图片描述

在这里插入图片描述

一个传输轮次:发送了一批报文段并收到他们的确认的时间/一个往返时延RTT/开始d发送一批拥塞窗口内的报文段到开始发送下一批拥塞窗口内的报文段的时间。快重传和快恢复

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章