【TCP专题1】TCP协议接收窗口(Window size)介绍

为什么要关心TCP窗口?因为它提高了数据传输的速度,因此也提高了用户访问应用程序的体验。TCP Window size 以下简称“TCP接收窗口”。

什么是TCP接收窗口?

简而言之,它是TCP接收缓冲区,用于尚未由应用程序处理的传入数据。使用TCP头的窗口大小值字段将TCP接收窗口的大小传达给连接伙伴。该字段告诉链路伙伴在接收到确认之前可以在线路上发送多少数据。如果接收器无法尽快处理数据,则接收缓冲区将逐渐填充,并且确认数据包中的TCP窗口将减少。这将警告发送方它需要减少发送的数据量或让接收方有时间清除缓冲区。
TCP接收窗口
在上图中,客户端和服务器在通信时正在通告其窗口大小值。每个TCP标头将显示最新的窗口值,该值可以随着连接的进行而增大或缩小。在此示例中,客户端具有65,535字节的TCP接收窗口,而服务器具有5,840字节。对于许多应用程序,由于客户端倾向于接收数据而不是发送数据,因此客户端通常具有更大的分配窗口大小。握手后,客户端将HTTP GET请求发送到服务器,该请求将得到快速处理。来自服务器的两个响应数据包到达客户端,客户端发送确认以及更新的窗口大小。客户端能够尽快处理来自TCP缓冲区的数据包,因此不会减小窗口大小。 客户端仍然具有可用于接收数据的完整窗口 65,535字节。
在另一个示例中,客户端正在从服务器请求数据并开始接收数据。但是,在这种情况下,客户端将无法快速处理传入的数据。如减小的窗口值所示,TCP缓冲区开始填充。
在这里插入图片描述
客户端的确认表明该窗口正在缩小。只要窗口值不降为零,最终用户就不会注意到这种行为。尽管数量有所减少,但缓冲区中仍有大量空间可以继续进行数据传输。在许多情况下,客户端可以追赶并处理缓冲区之外的数据,清除窗口并增加窗口值。

TCP窗口比例

分配给窗口大小的TCP标头值是两个字节长。这意味着接收窗口的最大可能数值是65,535字节。在当今的网络中,此窗口大小不足以提供最佳的流量,尤其是在长而胖的网络(具有高带宽和高延迟的链接)上。在其原始状态下,TCP一次只能发送最多65,535个字节,因此无法利用这些高性能链接。
因此,在 RFC 1323 使 TCP接收窗口成倍增加。特定功能称为TCP窗口缩放,该功能在握手过程中通告。在宣告其窗口时,客户端或服务器还将宣告将在连接有效期内使用的比例因子(乘数)。
在这里插入图片描述
在上图中,此数据包的发送方正在宣告63,792字节的TCP窗口,并且使用的比例因子为4。这意味着真实的窗口大小为63,792 x 4(255,168字节)。 使用缩放窗口允许端点通告超过1GB的窗口大小。若要使用窗口缩放,连接的两侧必须在握手过程中宣告此功能。如果一侧或另一侧不支持缩放,则任何一方都不会使用此功能。比例因子或乘数将仅在握手期间在SYN数据包中发送,并将在连接期间使用。这就是为什么在执行TCP分析时捕获握手过程如此重要的原因之一。

什么是零窗口?

当客户端(或服务器,但通常是客户端)的窗口大小公布为零时,表明TCP接收缓冲区已满,无法再接收任何数据。它可能有处理器卡住或正在忙于其他任务,这可能导致TCP接收缓冲区填满。零窗口也可能是由于应用程序中的问题导致的,其中没有检索TCP缓冲区。
在这里插入图片描述
来自客户端的TCP零窗口将中止来自服务器端的数据传输,从而使问题工作站有时间清除其缓冲区。客户端开始消化数据时,它将通过发送TCP窗口更新数据包让服务器知道恢复数据流。这将通告增加的窗口大小,并且流程将恢复。

–END
(部分图片源于网络,如需删除,请联系我)

  • 10
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 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
发出的红包

打赏作者

IT后院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值