Files
netstack/tcpip/transport/tcp/reno.go

104 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tcp
import (
"log"
"netstack/logger"
)
type renoState struct {
s *sender
cnt int
}
// 新建reno算法对象
func newRenoCC(s *sender) *renoState {
return &renoState{s: s}
}
// updateSlowStart 将根据NewReno使用的慢启动算法更新拥塞窗口。
// 如果在调整拥塞窗口后我们越过了 SSthreshold ,那么它将返回在拥塞避免模式下必须消耗的数据包的数量。
func (r *renoState) updateSlowStart(packetsAcked int) int {
// 在慢启动阶段,每当收到一个 ACKcwnd++; 呈线性上升
oldcwnd := r.s.sndCwnd
newcwnd := r.s.sndCwnd + packetsAcked
// 判断增大过后的拥塞窗口是否超过慢启动阀值 sndSsthresh
// 如果超过 sndSsthresh ,将窗口调整为 sndSsthresh
if newcwnd >= r.s.sndSsthresh {
newcwnd = r.s.sndSsthresh
r.s.sndCAAckCount = 0
}
// 是否超过 sndSsthresh packetsAcked>0表示超过 没超过就是0
packetsAcked -= newcwnd - r.s.sndCwnd
// 更新拥塞窗口
r.s.sndCwnd = newcwnd
r.cnt++
logger.GetInstance().Info(logger.TCP, func() {
logger.NOTICE("一个 RTT 已经结束", atoi(oldcwnd), "慢启动中。。。 reno Update 新的拥塞窗口大小: ", atoi(r.s.sndCwnd), "轮次", atoi(r.cnt))
})
return packetsAcked
}
// updateCongestionAvoidance 将在拥塞避免模式下更新拥塞窗口,
// 如RFC5681第3.1节所述
// 每当收到一个 ACK 时cwnd = cwnd + 1/cwnd
// 每当过一个 RTT 时cwnd = cwnd + 1
func (r *renoState) updateCongestionAvoidance(packetsAcked int) {
// sndCAAckCount 累计收到的tcp段数
r.s.sndCAAckCount += packetsAcked
// 如果累计的段数超过当前的拥塞窗口,那么 sndCwnd 加上 sndCAAckCount/sndCwnd 的整数倍
if r.s.sndCAAckCount >= r.s.sndCwnd {
r.s.sndCwnd += r.s.sndCAAckCount / r.s.sndCwnd
r.s.sndCAAckCount = r.s.sndCAAckCount % r.s.sndCwnd
}
}
// 当检测到网络拥塞时,调用 reduceSlowStartThreshold。
// 它将 sndSsthresh 变为 outstanding 的一半。
// sndSsthresh 最小为2因为至少要比丢包后的拥塞窗口cwnd=1来的大才会进入慢启动阶段。
func (r *renoState) reduceSlowStartThreshold() {
r.s.sndSsthresh = r.s.outstanding/2
if r.s.sndSsthresh < 2 {
r.s.sndSsthresh = 2
}
}
// HandleNDupAcks implements congestionControl.HandleNDupAcks.
// 当收到三个重复ack时调用 HandleNDupAcks 来处理。
func (r *renoState) HandleNDupAcks() {
// A retransmit was triggered due to nDupAckThreshold
// being hit. Reduce our slow start threshold.
// 减小慢启动阀值
r.reduceSlowStartThreshold()
}
func (r *renoState) HandleRTOExpired() {
// We lost a packet, so reduce ssthresh.
// 减小慢启动阀值
r.reduceSlowStartThreshold()
// Reduce the congestion window to 1, i.e., enter slow-start. Per
// RFC 5681, page 7, we must use 1 regardless of the value of the
// initial congestion window.
// 更新拥塞窗口为1这样就会重新进入慢启动
log.Fatal("重新进入慢启动")
r.s.sndCwnd = 1
}
// packetsAcked 已经确认过的数据段数
func (r *renoState) Update(packetsAcked int) {
// 当拥塞窗口没有超过慢启动阀值的时候,使用慢启动来增大窗口,
// 否则进入拥塞避免阶段
if r.s.sndCwnd < r.s.sndSsthresh {
packetsAcked = r.updateSlowStart(packetsAcked)
if packetsAcked == 0 {
return
}
}
// 当拥塞窗口大于阈值时 进入拥塞避免阶段
r.updateCongestionAvoidance(packetsAcked)
}
func (r *renoState) PostRecovery() {
// 不需要实现
}