21-TCP 协议(滑动窗口——抓包分析)

在上一文中我们已经介绍了滑动窗口的基本概念,以及它的目的。本文我们就亲自动手实践一下。

1. 环境准备

git 地址:https://git.oschina.net/ivan_allen/unp.git

  • 服务器:unp/protocol/tools/tcpserver/sink_serv.c,部署在 Linux 上。
  • 客户端:/home/allen/unp/protocol/tools/winclient/sink_client.cpp,部署在 Windows 上。

服务器之所以叫 sink_serv,是因为它就是个黑洞,它接收到数据后就直接扔了,即石沉大海了(实际上,代码中将接收到的数据打印在屏幕上了)。服务器每隔 500 毫秒从接收缓冲区读一次数据,一次最多读 1024 字节。

客户端每次向服务器发送 1024 字节的数据,本质上是向自己的发送缓冲区写入 1024 字节数据。连续发送 count 次,count 可以通过命令行参数指定。

2. 实验

  • 启动服务器


这里写图片描述
图1 服务器启动

从图 1 中我们看到服务器最后一个启动参数是 4096,它表示将接收缓冲区大小设置为 4096. 然而,内核在设置缓冲区大小的时候,会把缓冲区大小设置为这个值的 2 倍(具体原因请参考 man 手册),因此可以看到第 4 行打印 actual recvbufsize:8192.

  • 在 windows 上打开 OmniPeek 准备抓包,同时启动客户端
sink_client.exe 192.168.80.129 8000 8

参数 8 表示客户端连续发送 8 次数据,每次 1024 字节。

3. 抓包结果


这里写图片描述
图2 OmniPeek 抓包结果


这里写图片描述
图3 时序图

在时序图中,ACK n 表示对序号为 n 的 TCP 段进行确认。


这里写图片描述
图4 滑动窗口分析

图 4 中,我们用绿色表示发送方,蓝色表示接收方加送的信号。在一开始的时候,接收方通告了一个大小为 2920 大小的窗口,接下来发送方发送了 4 号报文,大小为 1024 B,然后接收方确认了 4 号报文,并通告了一个大小为 2920 大小的窗口。后面依此类推。

4. 总结

  • 掌握滑动窗口的工作原理

最后再次强调一下,学习滑动窗口,我们假设网络是理想的,不拥塞,只要发了数据,对方一定能收到。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的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、付费专栏及课程。

余额充值