端口号的了解
通常进行通信时,发送方使用任意端口,指定接收方为指定端口,因为接收方在接收到后的需要根据发送方指定的接收方端口号,来选择使用哪一个服务进程进行处理。
端口号还可以分类为两个大类:
TCP和UDP报文的对比
Tcp的流量控制
流量控制总览
TCP 流量控制是一种机制,用于根据接收方的处理能力动态调节发送方的数据发送速率。接收方通过 接收窗口 (rwnd
) 通知发送方当前的缓冲区剩余空间,发送方根据 rwnd
大小调整发送数据量,防止数据超出接收方的接收能力并避免缓冲区溢出。
发送窗口(swnd)
接收窗口(rwnd)
流量控制的例子
首先这里的初始rwnd是在tcp三次握手的时候从接收方得知的。
初始发送窗口为400表示最多可以发送400个字节,在发送了300个字节之后,还未来得及发送301-400字节就收到了接收方的ack201,表示接收成功了前200个字节,并且告知接收窗口此时为300字节,虽然初始发送方窗口为400,但是流量控制中规定发送方的发送窗口大小受到接收方接收窗口的限制,所以发送方发送窗口调整为300。
此时只能发送201-500共300字节,201-300已经发送过了,虽然还未收到对应ack,但是必须等超时之后才能发送,所以此时只需将301-500字节发送。后面超时重传201-300。后面也是一样的套路。
当发送方收到0窗口通知(rwnd=0)那么此时发送方窗口也设为0,此时不能发送数据,因为接收方缓冲区满了,正在不断处理数据,直到后面接收方处理好之后会发送一个不为0的rwnd通知。收到这个通知之后接收方可以继续发送数据。
如果这个不为0的rwnd通知丢失了(接收方也不会再次发送了,那么发送方接收方都一直等下去吗?),其实也没关系,因为发送方在收到0窗口通知(rwnd=0)的时候就其实启动了一个定时器,定时器结束,就会向接收方发送一个1字节的0窗口探测报文,接收方可以对其进行回应。
这里的图片没有展示rwnd=0之后的事情,后面用的纯文字描述的,如果觉得抽象的话,可以观看视频:5.4 TCP的流量控制_哔哩哔哩_bilibili
Tcp的拥塞控制
拥塞控制
TCP的拥塞控制中,主要包含如下的四个具体控制机制:
拥塞窗口(cwnd)和慢开始门限(ssthresh)
这里为了便于讨论,所以我们暂时先不考虑流量控制,所以直接假定发送窗口的大小=发送方拥塞窗口大小。实际上后面我们综合考虑的时候,发送方窗口(swnd)=min{接收窗口(rwnd) , 拥塞窗口(cwnd)}
cwnd 是 TCP 拥塞窗口(Congestion Window)的缩写,它是 TCP 拥塞控制中的一个关键概念,表示发送方在没有接收到确认(ACK)之前,能够发送的数据量的最大值。换句话说,cwnd 决定了在网络中发送数据时,发送方可以在没有收到确认的情况下“拥塞控制”允许发送的数据量。
慢开始和拥塞避免
慢开始 (Slow Start)
- 目的:在连接开始或网络空闲时,逐步增加传输速率,防止网络拥塞。
- 过程:从一个小的初始拥塞窗口(
cwnd
)开始,每次收到一个 ACK 就将cwnd
值加倍,呈指数增长,直到达到一个预设的慢启动阈值 (ssthresh)。 - 限制:当达到
ssthresh
值时,进入拥塞避免阶段。
拥塞避免 (Congestion Avoidance)
- 目的:在高负荷时,平缓增加传输速率,以避免网络过载。
- 过程:
cwnd
以线性速度增长,每个传输轮次只增加一个 MSS,确保流量控制更精细。 - 触发:一旦
cwnd
达到或超过ssthresh
,即进入拥塞避免状态。 - 限制:当发送方对于任意已发送报文,在报文重传计时器倒计时结束前没有收到接收方传来的ack确认,那么发送方将会认为是网络中发生了拥堵。此时重新转为慢开始机制,将ssthresh值设置为当前cwnd的一半,然后cwnd变为1。
- “慢开始”是指一开始向网络注入的报文段少,并不是指拥塞窗口cwnd增长速度慢;慢开始阶段的数量增加是每次翻倍,非常快。
- “拥塞避免”并非指完全能够避免拥塞,而是指在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。
为什么需要快重传+快恢复?
这里我们可以采取一个措施,以此来尽量避免由于误判网络状态导致的重新慢启动,方法就是采用快重传。赶在因意外丢失的数据报对应的发送方定时器结束前,重新发送一次这个数据报,这样我们就很大可能性在定时器结束前,将第二次的数据报送到接收方,并且收到接收方对于这个报文序列的ack。如此一来,就可以避免定时器超时造成的慢启动。但是我们应该如何在定时器结束前知道这个报文丢失了呢?
在正常情况下,如果发生丢包,TCP 会根据 3 次重复 ACK 来触发快速重传,而无需重新回到 慢启动。只有当超时发生时,才会回到慢启动。发送方收到连续三次重复ACK,就会重传该报文。
重复ACK是什么呢?别急,下面将详细解释一下:
正常的 ACK:
- 当发送方发送一系列的数据包时,接收方每收到一个数据包,就会返回一个 ACK,告知发送方已经成功接收的数据的序列号。
- 比如,发送方发送了数据包 1、2、3、4、5,接收方收到数据包 1 和 2 后,会发送
ACK 3
,表示接收到的数据包序列号 1 和 2(下一个期望的包是 3)。丢包后的重复 ACK:
- 假设发送方发送了数据包 1、2、3、4、5,但数据包 3 丢失了。
- 接收方收到了数据包 1 和 2,然后会发送
ACK 3
(表示接收到了数据包 1 和 2,期待数据包 3)。- 当接收方收到数据包 4 后,它会发现自己缺少数据包 3,于是仍然会发送
ACK 3
,表示它仍在等待数据包 3。- 同样,接收方收到数据包 5 后,还会发送
ACK 3
,因为它仍然没有收到数据包 3。重复 ACK 的含义:
- 在这个例子中,接收方连续发送了
ACK 3
(即重复的 ACK),表示它仍然在等待数据包 3。- 当发送方接收到三个重复的 ACK(例如接收到三个
ACK 3
),就可以认为数据包 3 丢失了,因此它会触发 快速重传 机制,立刻重传丢失的数据包,而无需等待 超时。
为什么收到重复ACK大概率能表明发生的是偶然丢包而不是网络拥塞?
在网络没有发生拥塞的情况下,个别TCP数据报可能会丢失,但是和它同一批次传送的几个数据报几乎不可能也丢失,它们会被接收方成功获取并且返回若干ack(由于前面的有个别报文丢失,所以接收方即使收到后面编号的数据报,返回的都是当前最小编号未确认接收的报文ACK)。
如果网络发生拥塞,大概率这一系列的TCP数据报都不会被收到,接收方也不可能连续返回重复ack(发送方收不到连续的重复ACK,就知道这应该不是偶然丢包,大概率属于网络拥塞)。
所以只要接收方收到连续重复ACK,大概率发生的是偶然丢包,没必要进行慢启动!!!
快重传和快恢复
发生偶然的丢包后,由于存在快重传+快恢复,所以不用慢启动,但是也不是接着之前的阻塞窗口继续累加,而是会将阻塞窗口值cwnd和慢开始门限调整为当前阻塞窗口值的一半,不用从1慢启动,直接进入了拥塞避免阶段
拥塞控制例子
这个例子中第一次属于网络发送了拥塞,超时重传,从慢启动开始;第二次属于偶然丢包,使用快重传和快恢复。
TCP流量控制和拥塞控制的对比
TCP超时重传时间的选择
TCP 超时重传时间(RTO, Retransmission Timeout)的选择是一个重要的动态过程,用于确保丢失的数据包可以被及时重传,同时避免不必要的重复发送。RTO 的选择主要基于网络往返时间(RTT)的估计,通常通过以下步骤来动态调整:
TCP 的超时重传时间 RTO 是一个动态调整的时间值,它结合了网络往返时间(RTT)的平滑估计 SRTT 和延迟抖动 RTTVAR,通过加权平均和指数退避策略,实现了更可靠的传输和更好的适应性。
超时重传例子
SRTT 和 RTTS 是同一个概念,表示平滑的 RTT(Smoothed RTT);同样,RTTVAR 和 RTTD 也是同一个概念,表示RTT 的变化范围或偏差(RTT Deviation)。
- SRTT(RTTS):这是对实际 RTT 的平滑估计,通过加权平均来减少波动影响。
- RTTVAR(RTTD):这是对 RTT 变化幅度的估计,用于表示 RTT 的偏差或不确定性。
这两个变量一起帮助动态调整 RTO,以适应网络延迟的正常变化。
TCP可靠传输的实现总结
这里有一个非常好的视频,详细包含了上面流量控制,拥塞控制以及超时时间的选择。
5.7 TCP可靠传输的实现_哔哩哔哩_bilibili