TCP和UPD详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP和UPD详解相关的知识,希望对你有一定的参考价值。
参考技术AUDP 首部格式
首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
TCP 首部格式
序号 :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
确认号 :期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。
数据偏移 :指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
确认 ACK :当 ACK=1 时确认号字段有效,否则无效。TCP 规定, 在连接建立后所有传送的报文段都必须把 ACK 置 1。
同步 SYN :在连接建立时用来同步序号。 当 SYN=1,ACK=0 时表示这是一个连接请求报文段 。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。
窗口 :窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
假设 A 为客户端,B 为服务器端。
三次握手的原因
第三次握手是为了 防止失效的连接请求到达服务器,让服务器错误打开连接 。
客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,==如果不进行三次握手,那么服务器就会打开两个连接==。如果有第三次握手,客户端会忽略服务器之后发送的对滞留连接请求的连接确认,不进行第三次握手,因此就不会再次打开连接。
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
四次挥手的原因
客户端发送了 FIN连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是 为了让服务器端发送还未传送完毕的数据 ,传送完毕之后,服务器会发送 FIN 连接释放报文。 也就是说为了==防止数据丢失== 。
TIME_WAIT作用
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
TCP 使用超时重传来实现可靠传输 :如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。
一个报文段从发送再到接收到确认所经过的时间称为往返时间 RTT,加权平均往返时间 RTTs 计算如下:
其中,0 ≤ a < 1,RTTs 随着 a 的增加更容易受到 RTT 的影响。
超时时间 RTO 应该略大于 RTTs,TCP 使用的超时时间计算如下:
其中 RTTd 为偏差的加权平均值。
窗口是缓存的一部分,用来暂时存放字节流。 发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小 。
发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收 。如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。
接收窗口只会对窗口内最后一个==按序到达==的字节进行确认 ,例如接收窗口已经收到的字节为 31, 34, 35,其中 31 按序到达,而 34, 35 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
流量控制是为了控制发送方发送速率,保证接收方来得及接收。
接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小 ,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
也就是说是 通过滑动窗口实现 的。
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。 流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度 。
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复 。
发送方需要维护一个叫做拥塞窗口(cwnd)的状态变量,注意拥塞窗口与发送方窗口的区别: 拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口 。
为了便于讨论,做如下假设:
接收方有足够大的接收缓存,因此不会发生流量控制;
虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 ...
注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。
如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
在发送方, 如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传 ,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。
慢开始和快恢复的快慢指的是 cwnd 的设定值 ,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
参考链接:
https://github.com/CyC2018/CS-Notes/blob/master/notes/ 计算机网络%20-%20传输层.md
TCP UPD详解
文章目录
TCP UDP协议
1. 概述
TCP、UDP协议是TCP/IP体系结构传输层中的两个重要协议。
如图所示为计算机网络四层模型:
**IP协议
**是网际层中的核心协议,它可以互联不同的网络接口,并向其上层提供无连接、不可靠的数据传输服务
。
TCP/IP体系结构的应用层中包含许大量的应用层协议,其中有些应用层协议需要使用可靠传输服务,例如浏览网页、传输文件等,这些数据一旦传输失败会造成无法挽回的危害。而有些则需要使用不可靠传输服务,例如音视频通话等,少量的数据传输错误并不会对播放造成大影响。
由于应用层需要使用可靠和不可靠两种传输服务,但IP协议只能提供不可靠传输服务,于是就需要传输层来提供可靠/不可靠的传输服务
。
其中TCP提供可靠性传输服务,UDP提供不可靠传输服务
。
TCP
:T
ransmission C
ontrol P
rotocol,传输控制协议
,为上层提供的是面向连接的可靠的数据传输服务
。使用TCP通信的双方,在传送数据之前必须首先建立TCP连接
(逻辑连接,而非物理连接)。数据传输结束后必须要释放TCP连接
。TCP为了实现可靠传输,就必须使用很多措施,例如TCP连接管理、确认机制、超时重传、流量控制、拥塞控制
等。TCP的实现复杂,报文首部较大,占用处理机资源比较多。
UDP
:U
ser D
atagram P
rotocol,用户数据报协议
,为其上层提供的是无连接的不可靠的数据传输服务
,因此不需要实现可靠传输的各种机制。使用UDP通信的双方,在传送数据之前不需要建立连接。UDP的实现简单,用户数据报首部比较小。
2. 端口号 复用 分用
端口号
:运行在计算机上的进程使用进程标识符PID
来区分,但是因特网上的计算机使用操作系统复杂,不同的操作系统又有不同格式的进程标识符,为了使运行在不同操作系统的计算机的应用进程之间能够进行通信,就必须使用统一的方法对TCP/IP体系的应用进程进行标识
,而这个标识方法就是**端口号
**,运输层使用端口号来区分应用层的不同应用进程。端口号只具有本地意义,即端口号只是为了标识本计算机应用进程,在因特网中,不同的计算机中的相同端口没有联系,你电脑上的8080端口跟我电脑上的8080端口一点关系没有。
发送方的复用 :应用层报文经过传输层TCP协议进行封装,称为TCP复用。应用层报文经过传输层UDP协议封装,称为UDP复用。传输层的报文经过网络层IP协议的封装,称为IP复用
接收方的分用:网络层使用IP协议解析接受的IP数据报,称为IP分用。传输层使用TCP协议解析接受的TCP数据报,称为TCP分用。传输层使用UDP协议解析接受的UDP数据报,称为UDP分用。
3. TCP
3.1 TCP首部格式
TCP协议处于传输层,它向上层(应用层)提供面向连接的可靠传输服务
,为了实现可靠传输,采用了**面向字节流
**的方式。
TCP在发送数据时从发送缓存中取出一部分或全部字节并给其添加一个首部使之成为TCP报文段后在发送给下层。一个TCP报文段由首部
和数据载荷
两部分组成,TCP实现连接管理、确认机制、超时重传、流量控制、拥塞控制这些功能都体现在它首部中各字段的作用。
TCP首部由两部分构成 :20字节的固定首部和最大40字节的扩展首部。也就是说,一个TCP首部的字节数在20~60字节之间。
源端口 :16比特,即两字节,写入源端口号,用于标识发送
该TCP报文段的应用进程。
目的端口 :16比特,即两字节,写入目的端口号,用于标识接受
该TCP报文段的应用进程。
假如我们使用web服务127.0.0.1:8080远程访问MySQL服务器48.104.60.218:3306;源端口就是我们自己的IP地址中的端口8080,目的端口就是MySQL服务器的IP地址中的端口3306。
接下来看看与TCP实现可靠性传输有关的三个字段 :序号、确认号、ACK。
序号 :占32比特,取值范围[0, 2^32 - 1],序号增加到最后一个后,下一个序号就又回到0。序号的值用来指出本TCP报文段**数据载荷**第一个字节的序号
。如图所示,首部的序号即为数据载荷第一个字节的序号122。
确认号 :占32比特,取值范围[0, 2^32 - 1],确认好增加到最后一个后,下一个确认好又回到0。确认号的值用于指出期望收到对方下一个TCP报文段的数据载荷的第一个字节的序号,同时也是对之前收到的所有数据的确认
。可以这样理解:若确认号为n,则代表之前已经成功接收到序号为n-1的报文段,下一次期望收到序号为n的报文段。只有ACK标识的值为1时,确认号字段才有效。
ACK :确标志位,取值为1时确认号才有效;取值为0时确认号无效。TCP规定,连接建立后所有的TCP报文段都必须把ACK置为1。
如图,客户端向服务端发送一个TCP数据报,序号为200代表此数据报的数据载荷部分的第一个字节的序号为200。确认号为800代表客户端已经收到服务端发送的序号为799号以及之前的数据报,现在想要序号为800的数据报
。ACK的值为1保证确认号有效。数据载荷长度代表此次传输的字节数。也就是说,此次传输的数据载荷部分的序号为 200 - 300。
数据偏移 :占4比特,并以4字节为单位。用于指出TCP报文段的数据载荷部分的起始处距离TCP报文段的起始处有多远。这个字段实际上是指出了TCP报文段的首部有多少个字节
。同时,它的值是首部字节数除以4的。首部的字节数范围为:20 ~ 60,所以数据偏移字段的值范围为 5~15,即 0101到1111。
保留 :占6比特,保留以后使用。目前值为0。
窗口 :占16比特,以字节为单位。指出发送本报文段的一方的接收窗口
。窗口值作为接收方让发送方设置其发送窗口的依据。这是以接收方的接受能力来控制发送方的发送能力,称为流量控制。需要注意的是,发送窗口的大小还取决于拥塞窗口的大小,也就是从接收窗口和拥塞窗口中取最小值。
校验和 :占16比特,用于检查整个TCP报文段在传输过程中是否出现了误码。
紧急指针 :占16比特,以字节为单位,用来指明紧急数据的长度。当发送方有紧急数据时,可将紧急数据插队到发送缓存的最前面,并立刻封装到一个TCP报文中进行发送。紧急指针会指出本报文段数据载荷部分包含了多长的紧急数据,紧急数据之后是普通数据。
SYN :同步标志位,在TCP连接建立时用来同步序号
。TCP规定,SYN值为1时代表正在建立连接,此报文段不能携带数据
。
FIN :终止标志位,用于释放TCP连接
。TCP规定,FIN值为1时代表正在释放连接,此报文段不能携带数据
。
RST :复位标志位,用于复位TCP连接。当RST为1时,表示TCP连接出现了异常,此时必须先断开连接,再重新建立连接。RST还用来拒绝非法报文段或拒绝TCP连接。
PSH :推送标志位,用来实现推送操作。当接受方收到该标志位为1的报文段会尽快上交应用进程,而不必等到接收缓存都填满后再向上交付。
URG :紧急标志位,与紧急指针字段共同实现紧急操作。紧急标志位URG为1时,紧急指针有效,为0时紧急指针无效。
选项 :选项中的字段都是可选值,扩展功能。选项的字节数可变
填充 :由于选项的字节数可变,那就使用填充字段确保报文段首部能被4整除。假如选项有3字节,那么填充就只有1个字节。
为什么一定要确保首部字节数要能被4整除?因为数据偏移字段的值是首部字节数除以4。
3.2 建立连接-三次握手
TCP是面向连接的协议,它基于运输连接来传送TCP报文段。TCP运输连接的建立和释放是每一次面向娘连接的通信中必不可少的过程
。
TCP运输连接分为以下三个阶段:
- 通过三次握手建立TCP连接
- 进行数据传输
- 通过四次挥手断开TCP连接
先来介绍一下TCP连接的建立 :三报文握手
最初,TCP客户端与TCP服务端的TCP进程都处于关闭状态
,即CLOSED
。
一开始,TCP服务端先创建TCP传输控制块,用于存储TCP连接中的以下重要信息,例如TCP连接表、指向发送和接受缓存的指针、指向重传队列的指针…TCP服务端创建传输控制块后就进入监听状态(LISTEN)
等待接受TCP客户端的连接请求。
TCP客户端在发起连接请求之前也要创建传输控制块,之后发起连接请求。
第一次握手
:
TCP客户端进程向TCP服务端进程发送TCP连接请求报文段
,并进入同步已发送状态(SYN-SEND)
。
此连接请求报文段首部中的值:
-
SYN :1,表明这是一个TCP连接请求报文段。同时规定此时的报文段不能携带数据。
-
序号(seq) :初始值x
第二次握手
:
TCP服务端接收到请求连接报文后,如果同意连接,会向TCP客户端发送 连接请求确认报文段
,并进入同步已接受状态(SYN-RCVD)
。
该报文段首部中的值:
-
SYN :1,表明现在正在进行TCP连接。同时规定此时的报文段不能携带数据。
-
ACK :使确认号生效。
-
确认号(ack) :由于客户端发送的序号为x,那么确认号就是x+1,代表“我已经收到序号为x以及之前的数据了,你下次给我发x+1吧”。
-
序号(seq) :初始值y。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4nZdkdLy-1678504984186)(assets/image-20230308181233-f7ep57n.png)]
第三次握手
:
TCP客户端收到连接请求确认报文段后,还需要向TCP服务端进程发送一个**普通
的TCP确认报文段
,并进入连接已建立状态(ESTABLISHED)
。由于是一个普通**的连接建立报文段,所以它的SYN字段值并不为1,所以这个报文段可以携带数据,但是它不携带数据。
(TCP规定,SYN为1的报文段不能携带数据,报文段发送时消耗一个序号。SYN不为1的报文段可以携带数据,如果不携带数据,不消耗序号)
该报文段的首部值:
- ACK :1,保证确认位可用。
- 序号(seq) :x+1,因为TCP服务端上次发的报文中的确认号为x+1。由于SYN值不为1,并且没有携带数据,故x+1这个序号下次还能用,也就是建立连接后还可以再使用一次x+1这个序号。
- 确认号(ack) :y+1,因为TCP服务端上次发送的报文段的序号为y,所以我们这次发送y+1,表示我们已经接收到了序号y以及之前的数据,下次我们想要序号为y+1的数据。
当TCP服务端接收到TCP客户端第二次报文时,服务端也进入连接已建立状态(ESTABLISHED)
。
现在,双方都已进入连接建立状态,可以根据已经建立好的TCP连接进行可靠的数据传输。
那么为什么建立TCP连接一定需要三次呢?为什么不能是两次?为什么不能使用两次报文握手建立连接呢?
接下来看看两报文握手会出现的问题 :
TCP客户端发出请求连接报文,但是因为网络问题长时间停滞在网络中,于是触发超时重传机制,TCP客户端重新发起TCP连接请求报文段,这次成功建立连接。之后便是数据的传输,最后数据传输完成,服务端与客户端断开连接。
断开连接后突然,上次因为网络问题滞后的TCP连接请求发送到了TCP服务端,服务端以为客户端想要再次建立TCP连接,于是服务端进入监听(LISTEN)状态并向客户端发送连接请求确认报文,但是客户端此时为关闭状态,对连接请求确认报文不予理睬,于是服务端一直处于监听状态并发送连接请求确认报文。这就造成了TCP服务端资源的浪费。
综上所述,采用三报文握手而不是两报文握手是为了防止已失效的连接请求报文段突然传送到了TCP服务端因而导致的错误
。
3.3 释放连接-四次挥手
TCP通过四次挥手来结束TCP的连接。
在断开连接之前,客户端与服务端都处于连接已建立状态(ESTABLISHED)
。
第一次挥手 :
TCP客户端会发送TCP连接释放报文段
,进入终止等待1状态(FIN-WAIT-1)
。TCP连接释放报文段的字段值为:
- FIN :1,代表此时正在释放TCP连接,此报文段不能携带数据。
- ACK :使确认号生效。
- seq(序号) :u,代表此报文段的数据载荷的第一个字节的序号为u。
- ack(确认号) :v,代表已经收到序号为v-1的数据,下次想要序号为v的数据。
第二次挥手
:
服务端接收到客户端发送的TCP连接释放报文段后,会向客户端发送一个普通的TCP确认报文段
,并进入关闭等待状态(CLOSE-WAIT)
。
(此时的TCP连接进入了半关闭状态,因为客户端到服务端的TCP连接进入关闭状态,因为客户端已经没有数据要发送了;但是服务端到客户端的TCP连接通道还没关闭,因为服务端要继续发送那些还未发送完毕的数据。)
此报文段的字段值 :
- ACK :1,保证确认号有效
- 序号(seq) :v,代表此报文段的数据载荷的第一个字节的序号为v。
- 确认号(ack) :u+1,代表已经收到客户端发送的第u条数据,下次想要u+1。
TCP客户端收到TCP服务端发送的TCP确认报文段后就会进入终止等待2状态(FIN-WAIT2)
。
第三次挥手
:
当TCP服务端所有剩余数据发送完毕后,TCP服务端会发送TCP连接释放报文段
,并进入最后确认状态(LAST-ACK)
。
该报文段的字段:
- FIN :1,表示正在释放连接。
- ACK :1,保证确认号有效。
- 序号(seq) :w,为什么不是v+1?因为第二次挥手之后可能传输了其他剩余数据报。
- 确认号(ack) :u+1。为什么是u+1?不是又发送了剩余数据吗?因为剩余数据报只是服务端向客户端发送,客户端向服务端的TCP连接通道已经断开。
第四次挥手
:
收到服务端发送的TCP连接释放报文段后,客户端发送普通的确认报文段
,之后进入时间等待状态(TIME-WAIT)
。
收到该报文段后,服务端关闭。处于时间等待状态2MSL(2mins)后,客户端TCP连接关闭。
该报文字段值 :
- ACK :1,保证确认号有效
- 序号(seq) :u+1
- 确认号(ack) :w+1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u0RBO0Rt-1678504984188)(assets/image-20230309151435-5c57p7p.png)]
为什么客户端还要等待两分钟再关闭TCP连接呢?
假如不进行等待而直接关闭,也就是客户端发送第四次挥手之后立即关闭TCP连接。那么如果最后一个确认报文丢失,此时客户端已经关闭,但服务端还在等待最后的确认保报文,一直没等到就会触发超时重传机制发送第三次挥手报文,但是客户端已经关闭,那么服务端就会一直发送第三次挥手报文,非常浪费资源。而等待两分钟就可以解决这个问题,客户端有足够时间等待服务端发送的超时重传报文。
至此,四报文挥手过程完毕。
接下来看看保活计时器 :
在客户端与服务端建立连接后,如果客户端出现故障,应当有措施让服务端主动断开连接而不是一直等待下去。这时就要使用到保活计时器。
- TCP服务器进程每收到一次TCP客户进程的数据,就重新设置并启动保活计时器(定时2小时)。
- 若2小时内没接收到TCP客户端发送的数据,则
当保活计时器到时后,TCP服务器向TCP客户端发送一个探测报文段,以后则每75秒发送一次,若连续10个报文段都无响应,TCP服务端主动断开TCP连接
。
3.4 TCP流量控制
为什么需要流量控制?一般来说,我们更加希望传输速度越快越好,但是如果发送方发送数据的速度过快,会导致接受方来不及接收,这就会造成数据的丢失。
所以流量控制就是为了让发送方发送的速率不要太快,要让接受方来得及接收
。
TCP的流量控制是通过滑动窗口来实现的。如果此时A向B传输数据,在传输数据前B告诉A:我的接收窗口rwnd=400(receiver window)。这表示 :发送方A的发送窗口不能超过接受方B的接收窗口的值,也就是400字节。
假如B最初的接收窗口大小为400,那么A可以发送400字节的数据。B接收400字节数据并发送确认后,这400字节的数据会先从A的发送缓存中删除。现在A成功向B发送了400字节的数据,但是B的接收缓存没多少空间了,于是B对A说:我的接收窗口为rwnd=300。这表示发送方A的发送窗口不能超过300字节。就这样,如果发送后B的发送缓存还没腾出空间,会继续减小接收窗口直到B的发送缓存没有空间,这时B向A发送的rwnd=0,即零窗口通知
,代表不要再发送数据了,等我腾出空间再说吧。
如果A发送的数据丢失怎么办呢?
A给B发送消息,如果数据丢失,并不会影响A后续数据的发送,B发送的ack消息会告诉A哪些数据还没有发送,到时A重新发送即可。
如果B发送的rwnd丢失怎么办呢?
如果B发送给A的rwnd丢失,A一直在等待B发送的窗口通知(rwnd)以便设置自己的发送窗口,而主机B以为A已经接收到窗口通知,他就一直等待A发送的数据,这就会造成死锁的局面。为了解决这个问题,TCP为每一个连接设置一个持续定时器
。
如果B给A发送零窗口通知,持续计时器会重新计时,当持续计时器超时时,证明已经很久没有收到零窗口通知了,A就给B发送一个探测报文,B接收该报文后,将自己的接收窗口值发送给A,如果此值为0,则持续计时器重新计时;如果此值为其他值,A将其发送窗口大小设置为此值。于是死锁问题得以解决。
3.5 TCP拥塞控制
拥塞 :对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就要变坏。这种情况叫做拥塞(congestion)
。
若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降。
TCP对拥塞控制提供了四种算法 :
- 慢开始(slow-start)
- 拥塞避免(congestion avoidance)
- 快重传(fast retransmit)
- 快恢复(fast recovery)
为了简单起见,我们假设发送方A,接收方B,A只发送数据报,B只发送确认报。并且接收方的接收窗口足够大,此时发送方的发送窗口就只受拥塞控制的影响。
发送方维护一个叫做拥塞窗口cwnd
的状态变量,其值取决于网络的拥塞程度,并且动态变化
。
- 拥塞窗口cwnd的维护原则:只要网络没有出现拥塞,拥塞窗口就再增大一些。网络出现拥塞,拥塞窗口就减小一些。
- 判断出现网络拥塞的依据:没有按时收到应当到达的确认报文段(即发生超时)
发送方将拥塞窗口作为发送窗口swnd,即swnd = cwnd。
具体的拥塞控制可以参考 :https://juejin.cn/post/6844903664566403085
实在是讲不出来😢
3.6 TCP可靠传输的实现
TCP基于以字节为单位的滑动窗口来实现可靠传输。
如图A与B建立了TCP连接
(简单起见,我们假设数据单方面发送并且没有拥塞影响,即A发送数据报文段,B只发送确认报文段,并且发送窗口不会受到拥塞控制的影响)
上方表格为待传输的数据的序号。
连接建立后B给A发送一个确认报文段:rwnd=20, ack=23,代表滑动窗口大小为20,下一次给我传序号为23的数据。
发送方接收到这个确认报文段后构造出自己的发送窗口,大小为20字节,发送窗口从序号为23的数据开始,它称为后沿;直到序号为42的数据结束,它称为前沿。
并且,由于ack=23,发送方A可以将23号以前的数据从发送缓存中删除,在接收到ack之前,发送窗口中的数据都要留在发送缓存中。
发送窗口中的数据都是可以发送的数据,发送窗口前沿右边的数据都是不允许发送的数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5SWkMJ5-1678504984188)(assets/image-20230310181508-0jd6o6q.png)]
后沿的移动情况有两种 :不动、前移
前沿的移动情况有三种 :不动、前移、后移。
接下来A向B发送10个字节的数据,序号为23-33的数据被发送出去,但是并不会从发送缓存中删除,因为还没有收到确认ack。
假如接收方B收到了序号为25-27的数据,由于23-24的数据还没接收到,所以B发送的确认报文的确认号仍为23。这是接收方对23号数据发起的第一次重复确认,因此不会触发超时重传机制。同时接收窗口为20没变。
当以后23-24号数据传到接收方,接收方就会发送对于23-27号数据的确认报文,如果rwnd的值仍为20,接收方就会将接收窗口移动到28-47号数据。
发送方收到该确认报文后将23-27号数据从发送缓存中删除。同时发送窗口移动到28-47号数据。
当发送方发送的数据迟迟无法到达接收方,重传计时器超时,会重传发送窗口内已发送的数据,并重新启动重传计时器
。
注意 :
-
虽然发送方的发送窗口是根据接收方的接收窗口设置的,但是在同一时刻,发送方的发送窗口并不总是和接收方的接收窗口一样大。
因为网络具有一定的延时性。
-
对于不按序列号到达的数据应该如何处理,TCP并无明确规定
- 如果丢弃,虽然实现更简单了,但是会浪费很多网络资源。
- 通常存储在接收窗口中,等到字节流中所缺少的字节收到后,再按序号交付给上层的应用进程。
-
TCP要求接收方必须有
累积确认
和捎带确认机制
,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息捎带上。但是接收方不应该过分推迟发送确认消息,否则会触发超时重传浪费资源。 -
TCP是全双工通信
,通信双方都在发送和接受报文段,因此,每一方都有自己的发送窗口和接收窗口。在谈到这些窗口时,一定要区分开。
3.7 TCP超时重传
刚才一直再说如果有一段报文迟迟没有发送会触发超时重传,但并没有说如何选择重传的时机,现在就来说说TCP对于超时重传的时机选择。
超时重传时间(RTO)
的选择是计算机网络最复杂的问题之一。
假如发送方为A,接收方为B。发送方A向接收方B发送数据报,并记录时间,A收到B的返回的确认报文段后再次记录时间。
这两个时间的差值为往返时间RTT
。如果超时重传时间设置的比RTT小很多,会触发不必要的重传。如果设置的比RTT大很多,迟迟不超时重传太影响效率。所以我们要找到一个正好的时间,这个时间比RTT大一点,但大的不多。
听起来很简单,但是复杂的网络环境使传输速率复杂多变,RTT也跟着变化,早上跟晚上的网络速率差别都很大。所以超时重传时间(RTO)的选择是计算机网络最复杂的问题之一。
这时候就不能以单次RTT的值确定RTO的值,而是使用很多次RTT的值通过一定的算法来计算出一个更加合适的RTO。
我们使用RTT代表通过计算得出的RTT的值,RTT(i)代表每一次TCP通信产生的RTT值
当第一次RTT产生时,最终RTT的值等于第一次RTT的值。RTT = RTT(1)
RTT多起来的时候,使用公式 :
RTT = (1-a)* 上一次RTT + a*RTT(i)
在上式中,0 ≤ a < 1,若a接近于0,则RTT(i)对RTT的值的影响不大。若a接近于1,则RTT(i)对RTT的影响较大。标准RFC298建议a的值为1/8
当通过每一次的样本计算得出最终RTT后,我们就可以规定超时重传时间RTO略大于RTT了。
至此,TCP就告一段落了。
4. UDP
由于UDP向应用层提供无连接不可靠的通信服务
,所以它无需像TCP那样实现流量控制、拥塞控制等等功能,它的字段也十分简单。
一个UDP用户数据报同样由首部与数据载荷两部分组成,首部格式如图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ATMS6yO6-1678504984189)(assets/image-20230310190305-vf2p1ze.png)]
它只有四个字段,每个字段两个字节共八个字节。由于UDP提供无连接不可靠的服务,所以它只在网际层的基础上添加了端口号的区分。
至此,UDP告一段落。。。才怪,UDP的功能会在下小节UDP与TCP的区别中注明。因为实在太少。。。
5.TCP与UDP的区别
TCP与UDP所有的区别都是基于一个条件 :TCP提供有连接可靠性传输服务,UDP提供无连接不可靠服务。
如果TCP不提供可靠服务,那他俩就一样了。
-
TCP传输数据前需要三报文握手建立连接,传输数据结束时四报文挥手断开连接。
UDP可以随时发送数据。只要你知道它的IP就可以突然发送数据。
-
TCP只支持一对一的solo模式,连接只能在两个主机之间进行。
UDP支持单播、多播、广播。
-
当应用层报文发送到传输层时
TCP将应用层传输的报文拆分为多个字节流标上序号,再加上TCP首部封装为TCP数据报,再根据发送策略发送给下层。TCP是面向字节流的。
UDP仅仅将应用层报文首部添加一个UDP首部封装为UDP数据报,就将该数据报发送给接受方。UDP是面向数据报的。
-
如果数据传输过程中数据丢失、误码
TCP会重新发送或触发重传机制。
UDP啥也不干。
最后,对比一下UDP数据报首部以及TCP数据报的首部格式:
以上是关于TCP和UPD详解的主要内容,如果未能解决你的问题,请参考以下文章