20-TCP 协议(滑动窗口——基础)

相信大家都遇到过这样的场景:

同学 Luffy 给你打电话,让你记下一串手机号码,可是你记忆力不太好,你跟 Luffy 约定,一次只最多只能报 4 个数字,Luffy 念一遍,如果你听到了就把他说的话重复一遍。接下来:

  • 你:你一次最多报 4 个数字,多了我记不住啊!
  • Luffy:139
  • 你:139 (Luffy 知道你听到了)
  • Luffy:7548
  • 你:7538 (很明显你听错了)
  • Luffy:不对,是7548
  • 你:7548
  • Luffy : 2669
  • 你:2669

最后,你接收到的完整的号码就是 139-7548-2669.

1. 滑动窗口

上面的场景,你一次最多只能接受 4 个数字,表示你的滑动窗口大小就是 4. 在 TCP 协议中,也有这样的滑动窗口,它的大小表示目前还能接收多少字节的数据。

TCP 每次收到对方发来的报文,都会检查窗口大小字段,见图 1.

这里写图片描述

图1 TCP 首部中有一个字段——16 位窗口大小

知道了对方的窗口大小后,就知道对方目前还能接收多少数据,接收的数据字节序号是 TCP 段中的 ACK 的值到 ACK + 窗口大小,即 [ A C K , A C K + 窗 口 大 小 ) [ACK, ACK + 窗口大小) [ACK,ACK+).

比如,你给对方发送了一个段携带字节序号为 [400, 500) 的数据。对方回送了一个 TCP 段,ack = 500, win = 100,就表示,我已经收到 [400, 500) 的数据我还能接收字节序号为 [500, 600) 之间的数据,见图 2。

这里写图片描述

图2 滑动窗口

修正:上面的第二条蓝线文字更改为 data[500, 600)

如果对方回送了一个 TCP 段,ack = 500, win = 0,就表示,我已经收到了 [400, 500) 的数据,但是我现在不能再接收数据了,你待会再发。

这里写图片描述

图3 对方回送 0 大小的窗口,接收端的反应

2. 滑动窗口的目的

回顾本文开头给出的打电话的例子,为什么你要告诉对方一次最多只能报 4 个数字?原因在于你的接受能力有限,不是说你无法记忆很多数字,只是在短期内,你记不住,你需要一段一段的记忆(一段一段的将数据放入缓冲区)。

所以,在 TCP 中,滑动窗口是为了实现流量控制。如果对方发送数据过快,接收方就来不及接收(你来不急记住),接收方就需要通告对方,减慢数据的发送(图 3)。

需要特别注意的是,在学习滑动窗口的时候,我们假设网络无限好,不拥塞。只要你发送了数据,对方一定可以收到。

再解释一下网络拥塞的含义,它是指你发送的数据滞留在网络中,迟迟未到达接收方。

3. 滑动窗口模拟

这里写图片描述

图4 滑动窗口模拟

修正:图4 中最后一个小图修正一下文字,应该为『发送方收到 ack=41, win=10, 知道对方希望接收序号为 [41, 51) 的数据』

  • 发送方接收到了对方发来的报文 ack = 33, win = 10,知道对方收到了 33 号前的数据,现在期望接收 [33, 43) 号数据。发送方连续发送了 4 个报文段假设为 A, B, C, D, 分别携带 [33, 35), [35, 36), [36, 38), [38, 41) 号数据。
  • 接收方接收到了报文段 A, C,但是没收到 B 和 D,也就是只收到了 [33, 35) 和 [36, 38) 号数据。接收方发送回对报文段 A 的确认:ack = 35, win = 10。
  • 发送方收到了 ack = 35, win = 10,对方期望接收 [35, 45) 号数据。接着发送了一个报文段 E,它携带了 [41, 44) 号数据。
  • 接收方接收到了报文段 B: [35, 36), D:[38, 41),接收方发送对 D 的确认:ack = 41, win = 10. (这是一个累积确认
  • 发送方收到了 ack = 41, win = 10,对方期望接收 [41, 51) 号数据。
  • ……

需要注意的是,接收方接收 tcp 报文的顺序是不确定的,并非是一定先收到 35 再收到 36,也可能是先收到 36,37,再收到 35.

4. 总结

  • 理解滑动窗口的工作过程
  • 滑动窗口的目的是什么?

下一篇文章,我们得抓个包来分析一下。

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
以下是一个简单的TCP协议滑动窗口源代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_SEQ_NUM 8 // 最大序列号 #define WINDOW_SIZE 4 // 滑动窗口大小 // TCP数据包结构体 typedef struct { int seq_num; // 序列号 char data; // 数据 } packet; int main() { packet send_buffer[MAX_SEQ_NUM]; // 发送缓冲区 packet receive_buffer[MAX_SEQ_NUM]; // 接收缓冲区 int next_seq_num = 0; // 下一个要发送的序列号 int ack_expected = 0; // 期望收到的确认号 int receive_window_size = 0; // 接收窗口大小 int send_window_size = 0; // 发送窗口大小 // 初始化发送缓冲区 for (int i = 0; i < MAX_SEQ_NUM; i++) { send_buffer[i].seq_num = i; send_buffer[i].data = 'A' + i; } // 模拟发送过程 while (ack_expected < MAX_SEQ_NUM) { // 发送窗口未满 if (next_seq_num < ack_expected + WINDOW_SIZE) { // 发送数据包 printf("Sending packet %d\n", next_seq_num); // 将数据包加入发送缓冲区 send_buffer[next_seq_num].seq_num = next_seq_num; send_buffer[next_seq_num].data = 'A' + next_seq_num; // 更新发送窗口大小 send_window_size++; // 发送下一个数据包序列号 next_seq_num++; } // 接收数据包 printf("Receiving packet\n"); // 模拟数据包丢失 if (rand() % 2 == 0) { printf("Packet lost\n"); continue; } // 从接收缓冲区中取出数据包 int seq_num = receive_buffer[ack_expected % WINDOW_SIZE].seq_num; // 如果收到期望的数据包 if (seq_num == ack_expected) { // 更新接收窗口大小 receive_window_size++; // 输出收到的数据包信息 printf("Received packet %d\n", ack_expected); // 更新期望收到的确认号 ack_expected++; // 从接收缓冲区中移除数据包 receive_buffer[ack_expected % WINDOW_SIZE].seq_num = -1; } // 发送确认包 printf("Sending ack %d\n", ack_expected); // 模拟确认包丢失 if (rand() % 2 == 0) { printf("Ack lost\n"); continue; } // 更新发送窗口大小 send_window_size--; // 从发送缓冲区中移除已确认的数据包 send_buffer[ack_expected].seq_num = -1; } printf("All packets sent and acknowledged\n"); return 0; } ``` 这段代码模拟了一个简单的TCP协议滑动窗口的实现过程。在实际的网络通信中,TCP协议滑动窗口还有很多细节需要考虑,这里只是一个简单的示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值