KCP 的滑动窗口TCP 大体相同。倘若深入探究源码,便会发觉之前那些难以理解的理论,在实现方面只有寥寥几行代码。接下来,看看 KCP 是怎样达成这些机制的。
TCP的可靠传输的实现–滑动窗口
倘若您未曾了解过滑动窗口,不妨观看以下 12 分钟的视频。我敢赌 5 块钱,您看完后肯定能理解滑动窗口机制。
https://www.bilibili.com/video/BV194411h71z/?spm_id_from=333.337.search-card.all.click
KCP中的滑动窗口
窗口大小
kcp和TCP一样,也是全双工的,所以不单有发送窗口,也有接收窗口。
发送窗口由远端窗口和拥塞窗口共同决定。
//发送窗口,调用ikcp_wndsize配置,默认32,
kcp->snd_wnd = IKCP_WND_SND;
//接收窗口,调用ikcp_wndsize配置,默认128,同时必须要大于128
kcp->rcv_wnd = IKCP_WND_RCV;
//对端窗口,接收端ack时,会将wnd带过来
kcp->rmt_wnd = IKCP_WND_RCV;
//拥塞窗口,动态计算,后边会讲到
kcp->cwnd = 0;
发送方的滑动窗口控制
-
发送方维护一个
snd_buf队列,保存已经发送但尚未确认的 Segment。 -
当发送新的 Segment 时,会检查
snd_wnd和cwnd,确保在窗口范围内发送。 -
每次发送数据时,发送窗口滑动,新的数据包进入窗口,并放入
snd_buf中。
接收方滑动窗口控制
-
接收方维护一个
rcv_buf队列,保存接收到但尚未处理的 Segment。 -
当接收到一个新的 Segment 时,首先检查其是否在接收窗口范围内 (
rcv_wnd)。 -
接收窗口滑动,将新的数据包放入
rcv_buf,并从窗口中移除已经确认的数据包。
窗口滑动的实现(以发送窗口为例)
滑动窗口犹如节假日时的高铁站。在安检处,有一位工作人员把控着人员的入场。安检处外,人员有序地排着队,而安检处内同样存在一个小队伍,大家都在有条不紊地进行安检。这个小队伍的最大长度,就是窗口的大小,倘若安检处里的人员过多,工作人员便会禁止人员入场;一旦有一部分人完成安检得以放行,工作人员就会再度允许人员进入。
我们把第一个进入高铁站的人设置编号为0,然后接下来排队的人编号递增,
定义 snd.una为下一个进入高铁站的人员编号
定义 snd.nxt 为下一个进入安检口的人员编号,
那么 snd.nxt - send.una 就是安检处的人数,也就是发送了但未收到确认的的数据包的个数,
snd.una + snd.wnd - snd.nxt 就是还可以进入安检的人数,也就是可用窗口的大小。
编号小于snd.una的人,意味着已经进入高铁站了,我们就不用管了,
具体可以结合如下图示理解。

接收发送窗口的基本实现和发送窗口一致,具体参考下图,

滑动窗口的源码解析
滑动窗口中的队列
| 名称 | 作用 | 说明 |
|---|---|---|
| snd_buf | 存储已经发送但尚未收到 ACK 确认的数据段 | 当一个数据包被发送后,它会被放入 snd_buf 中,直到收到对端的确认 (ACK)。KCP 通过这个队列来追踪未确认的数据包,并在需要时进行重传 |
| rcv_buf | 存储接收到但尚未被应用层处理的数据段 | 当 KCP 接收到一个数据段时,如果该段是乱序到达的(即序列号不连续),它会被放入 rcv_buf 中。接收窗口在等待正确的序列号时,乱序数据会保留在这个队列中,直到可以被应用层处理 |
| snd_queue | 存储待发送的数据段 | 应用层调用 ikcp_send() 将数据传递给 KCP 协议栈后,数据会被切分成多个数据段并放入 snd_queue 中。KCP 会根据窗口大小和拥塞控制机制,从这个队列中取出数据段进行发送 |
| rcv_queue | 存储已经按照正确顺序接收的数据段,等待应用层处理 | 一旦数据段的序列号符合接收窗口的预期(即接收方期望的下一个序列号),这些数据段会被从 rcv_buf 移动到 rcv_queue 中,并等待应用层读取 |
snd_nxt的更新
只要发送窗口有空闲,就把send_queue中的数据移动到snd_buf
void ikcp_flush(ikcpcb *kcp)
{
.....
// calculate window size

最低0.47元/天 解锁文章
1885

被折叠的 条评论
为什么被折叠?



