[总结]TCP滑动窗口和SO_RCVBUF之间的关系

本文详细解析了TCP滑动窗口的工作原理及配置方法,包括窗口大小的设定时机、最大值限制、扩展窗口的应用场景,以及窗口移动的具体规则。

    在以Unix为核心的一些操作系统中,SO_RCVBUF选项决定了TCP窗口的大小,你设置为多少窗口就为多少。对于客户端,SO_RCVBUF选项必须在connect之前设置;对于服务器,SO_RCVBUF选项必须在listen前设置。因为TCP的窗口规模选项是在建立连接时用SYN与对方互换得到的。
    在Windows上可以随时设置,一但设置后,会随着下一个ACK包,或者普通数据包通告给对方最新的TCP窗口大小,需要注意的是此时窗口只能增大,不能减小,也就是说SO_RCVBUF设置的比上一次小的话,该值是不会作为新窗口大小通告给对方的。
#########################################################################

一、TCP的滑动窗口大小实际上就是socket的接收缓冲区大小的字节数

二、对于server端的socket一定要在listen之间设置缓冲区大小,因为,accept时新产生的socket会继承监听socket的缓冲区大小。对于client端的socket一定要在connet之前设置缓冲区大小,因为connet时需要进行三次握手过程,会通知对方自己的窗口大小。在connet之后再设置缓冲区,已经没有什么意义。

三、由于缓冲区大小在TCP头部只有16位来表示,所以它的最大值是65536,但是对于一些情况来说需要使用更大的滑动窗口,这时候就要使用扩展的滑动窗口,如光纤高速通信网络,或者是卫星长连接网络,需要窗口尽可能的大。这时会使用扩展的32位的滑动窗口大小。

四、滑动窗口听移动规则:

1、窗口合拢:在收到对端数据后,自己确认了数据的正确性,这些数据会被存储到缓冲区,等待应用程序获取。但这时候因为已经确认了数据的正确性,需要向对方发送确认响应ACK,又因为这些数据还没有被应用进程取走,这时候便需要进行窗口合拢,缓冲区的窗口左边缘向右滑动。注意响应的ACK序号是对方发送数据包的序号,一个对方发送的序号,可能因为窗口张开会被响应(ACK)多次。

2、窗口张开:窗口收缩后,应用进程一旦从缓冲区中取出数据,TCP的滑动窗口需要进行扩张,这时候窗口的右边缘向右扩张,实际上窗口这是一个环形缓冲区,窗口的右边缘扩张会使用原来被应用进程取走内容的缓冲区。在窗口进行扩张后,需要使用ACK通知对端,这时候ACK的序号依然是上次确认收到包的序号。

3、窗口收缩,窗口的右边缘向左滑动,称为窗口收缩,Host Requirement RFC强烈建议不要这样做,但TCP必须能够在某一端产生这种情况时进行处理。

你提到的“TCP滑动窗口“CRC校验”是计算机网络中的两个重要概念,虽然它们不属于C++语言本身,但在使用C++进行网络编程(如基于Socket的通信)时,理解这些机制对实现高效、可靠的通信至关重要。下面我将从C++网络编程的角度详细解释这两个概念,并说明其作用、实现方式以及可能涉及的代码结构。 --- ### 一、TCP滑动窗口(Sliding Window) **回答问题:** TCP滑动窗口TCP协议中用于流量控制的核心机制,它允许发送方在未收到确认的情况下连续发送多个数据包,从而提高传输效率。接收方通过通告窗口大小来告诉发送方还能接收多少数据,防止发送过快导致缓冲区溢出。 #### 在C++中的体现: 虽然滑动窗口由操作系统内核的TCP/IP协议栈自动管理,但C++程序员可以通过Socket API间接影响其行为,例如设置接收/发送缓冲区大小。 ```cpp #include <sys/socket.h> #include <iostream> int sockfd; socklen_t optlen = sizeof(int); int sndbuf = 65536; int rcvbuf = 65536; // 设置发送缓冲区大小(影响滑动窗口的行为) if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) { perror("setsockopt send buffer"); } // 设置接收缓冲区大小 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) { perror("setsockopt receive buffer"); } // 获取当前缓冲区大小 getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen); std::cout << "Receive buffer size: " << rcvbuf << std::endl; ``` > ⚠️ 注意:实际滑动窗口大小由TCP动态调整,受拥塞控制、RTT、ACK反馈等因素影响,应用层不能直接控制窗口滑动逻辑。 #### 原理解释: - **发送窗口**:已发送但未确认的数据范围。 - **接收窗口**:接收方还能容纳的数据量(由`rwnd`表示)。 - 滑动窗口机制实现了**流量控制**(Flow Control),避免接收方被压垮。 --- ### 二、CRC校验(Cyclic Redundancy Check) **回答问题:** CRC是一种检错码,用于检测数据在传输或存储过程中是否发生错误。TCP/IP协议栈在链路层(如以太网)、网络层(如PPP)或应用层中使用CRC来保证数据完整性。**注意:TCP本身不使用CRC校验,而是使用16位的校验(Checksum)字段来验证TCP报文段的完整性**,而CRC更多用于底层(如数据链路层)。 但在某些自定义协议或可靠UDP通信中,开发者可能会在C++中手动实现CRC校验。 #### C++实现一个简单的CRC-32校验示例: ```cpp #include <iostream> #include <vector> #include <cstdint> // 预生成CRC-32查找表 static uint32_t crc32_table[256]; void init_crc32_table() { for (uint32_t i = 0; i < 256; ++i) { uint32_t crc = i; for (int j = 0; j < 8; ++j) { if (crc & 1) { crc = (crc >> 1) ^ 0xEDB88320; } else { crc >>= 1; } } crc32_table[i] = crc; } } uint32_t crc32(const uint8_t* data, size_t len) { uint32_t crc = 0xFFFFFFFF; for (size_t i = 0; i < len; ++i) { uint8_t index = (crc ^ data[i]) & 0xFF; crc = (crc >> 8) ^ crc32_table[index]; } return crc ^ 0xFFFFFFFF; } // 使用示例 int main() { init_crc32_table(); std::string message = "Hello, TCP with CRC!"; uint32_t checksum = crc32(reinterpret_cast<const uint8_t*>(message.c_str()), message.size()); std::cout << "CRC32: " << std::hex << checksum << std::endl; return 0; } ``` #### 原理解释: - CRC基于多项式除法,具有很强的突发错误检测能力。 - 虽然TCP不使用CRC,但如果你在应用层设计私有协议(如通过UDP传输文件),加入CRC可以增强可靠性。 - 常见变种:CRC-16, CRC-32, CRC-CCITT。 --- ### 总结对比: | 特性 | TCP滑动窗口 | CRC校验 | |------------------|--------------------------------------|--------------------------------------| | 所属层次 | 传输层(TCP) | 数据链路层 / 应用层 | | 主要目的 | 流量控制、提高吞吐量 | 错误检测 | | 是否由OS自动处理 | 是(协议栈内部实现) | 否(需手动实现于应用或驱动) | | C++可干预程度 | 可通过setsockopt调节缓冲区 | 可完全由C++实现 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值