滑动窗口协议

滑动窗口协议是什么? 让我用一个超级简单的生活例子来解释,忘掉所有代码,我们来讲个故事。

故事:小明给小红寄送一套漫画书

假设小明要给小红寄一套10本的限量版漫画,每本书都按顺序编号(1到10)。

方式一:最笨的"发一等一"法 (Stop-and-Wait)

  1. 小明把第1本漫画打包,寄出去。
  2. 然后他就在家死等,什么也不干,直到小红收到后,打个电话说:"第1本收到了!"
  3. 小明听到后,才把第2本打包,寄出去。
  4. 再等小红的电话......

缺点:效率极低!小明大部分时间都在等待,快递员也一直在来回跑冤枉路。这就好比你发一条WebSocket消息,必须等服务器回复ACK,才能发下一条。


方式二:引入"滑动窗口"协议

小明觉得太慢了,他想了个新办法。他家门口有个小货架,这个货架最多只能放4本书 (这就是我们的 窗口大小 Window Size = 4)。

新规则如下:

  1. 批量发送 :小明一口气把第1、2、3、4本漫画全打包好,放到货架上,然后让快递员一次性全部拉走。现在,这4本"在路上"的书,就是所谓的"飞行中(In-Flight)的消息"。
  2. 等待确认:小明在自己的记事本上记下:1, 2, 3, 4已发。
  3. 窗口滑动
    • 过了一会儿,小红打来电话:"第1本收到啦!"
    • 小明在记事本上把"1"划掉。好极了!货架上空出了一个位置!
    • 他立刻把第5本漫画放到货架上,让快递员拉走。
    • 现在,他"在路上"的书变成了 2, 3, 4, 5。你看,这个"4本书的窗口"是不是像向右滑动了一格?

这个过程就叫滑动窗口 。它允许小明连续发送一定数量的消息而无需等待,大大提高了效率。


解答你的核心困惑

现在,我们来处理最关键的"丢包"和"去重"问题。

1. 如果丢失了就只重传丢失的那一个消息?

这取决于小明(发送方)和小红(接收方)的"智商",也就是协议的具体实现方式。主要有两种:

A) 比较"笨"但简单的策略 (Go-Back-N / 回退N帧)

假设第2本漫画在路上被快递弄丢了。

  • 小红的反应:她收到了第1本,然后满心期待第2本。结果,快递员送来了第3本!小红很固执,她说:"不行!我必须按顺序收,没收到第2本,后面的我都不要!" 于是她把第3本、第4本都拒收了。她会一直打电话给小明说:"我只收到了第1本哦!"(意思是"我下一个想要的是第2本")。
  • 小明的反应:他一直没等到"第2本收到"的电话(超时了)。他就明白了:"第2本肯定出事了!" 他会怎么做?他会把从第2本开始的所有书(2, 3, 4, 5...)全部重新寄一遍!

这就是你在我们之前那个Demo里看到的逻辑。 它的优点是接收方(服务器)的逻辑非常简单,只需要判断来的序号是不是我想要的就行。缺点是浪费带宽,因为明明第3、4本可能已经到了,却被无情地重传了。

B) 比较"聪明"但复杂的策略 (Selective Repeat / 选择性重传)

还是第2本丢了。

  • 小红的反应:她收到了第1本。然后等来了第3本。她想:"虽然第2本没到,但我先把第3本收下,找个空地方放着。" 然后第4本也到了,她也收下,也找地方放着。她会打电话告诉小明:"我收到了第1、3、4本!"
  • 小明的反应:他收到了1、3、4的确认,但在本子上一看,唯独第2本迟迟没有消息(超时了)。他明白了:"哦,原来只是第2本丢了!" 于是,他只把第2本重新寄过去
  • 小红收到补发的第2本后,把它和之前收到的3、4本按顺序整理好。完美!

总结你的第一个问题:

是的,最理想的情况下是只重传丢失的那一个。但这需要发送方和接收方都实现更复杂的逻辑(选择性重传)。在很多简单的实现中(比如我们那个Demo),为了简化逻辑,会采用"回退N帧"的策略,即从丢失的那个开始,后面的全部重传。

2. 服务端去重还是怎么着啊?

必须去重!你说到点子上了!

这是接收方(小红/服务器)一项非常重要的任务。

场景:假设小明因为超时,重传了第2本书。但其实原来的第2本书只是路上堵车,晚到了而已。

  • 小红的反应:
    1. 她先收到了那个"迟到"的第2本书。她很高兴,确认收入,并打电话给小明:"第2本收到啦!"
    2. 过了不久,快递员又送来一本第2本书(这是小明重传的)。
    3. 小红一看手里的记事本:"咦?第2本我不是已经收过了吗?" 她会直接把这本重复的书扔掉(或者退回),这就是去重。
    4. 为了保险起见,她可能会再给小明打个电话:"第2本我收到了哈!"(因为她怕上次的确认电话,小明也没接到)。

所以,接收方必须根据消息的序列号(Sequence Number)来判断这条消息是不是处理过,从而丢弃所有重复的消息。

总结一下

概念 大白话解释 你的问题解答
滑动窗口 一次可以发送的最大"未确认"消息数。像一个货架,装满了就得等确认才能上新货。 是批量发送,但这个"批量"的大小是受窗口限制的。
滑动 收到一个确认(ACK),窗口就空出一个位置,可以发下一条新消息了。 -
丢包重传 在规定时间内没收到确认,就认为丢了,要重发。 可以只重传丢失的那个(复杂方案),也可以从丢失的那个开始全部重传(简单方案)。
去重 接收方根据序列号,识别并丢弃已经收到过的重复消息。 对,服务端(接收方)必须做去重。 这是保证数据正确性的关键。

希望这个故事能让你彻底明白滑动窗口协议的精髓!它就是用一种巧妙的方式,在"效率"(批量发送)和"可靠性"(确认、重传、去重)之间找到了一个绝佳的平衡点。

相关推荐
盛夏绽放1 分钟前
接口验证机制在Token认证中的关键作用与优化实践
前端·node.js·有问必答
zhangxingchao18 分钟前
Jetpack Compose 之 Modifier(中)
前端
JarvanMo18 分钟前
理解 Flutter 中 GoRouter 的context.push与context.go
前端
pe7er24 分钟前
使用 Vue 官方脚手架创建项目时遇到 Node 18 报错问题的排查与解决
前端·javascript·vue.js
绝无仅有24 分钟前
对接三方SDK开发过程中的问题排查与解决
后端·面试·架构
星始流年27 分钟前
前端视角下认识AI Agent
前端·agent·ai编程
pe7er31 分钟前
使用 types / typings 实现全局 TypeScript 类型定义,无需 import/export
前端·javascript·vue.js
CH_Qing31 分钟前
【udev】关于/dev 设备节点的生成 &udev
linux·前端·网络
西岭千秋雪_34 分钟前
Redis缓存架构实战
java·redis·笔记·学习·缓存·架构
小诸葛的博客36 分钟前
gin如何返回html
前端·html·gin