《TCP/IP详解 卷一》第15章 TCP数据流与窗口管理

小明 2025-05-04 16:45:26 6

���录

15.1 引言

15.2 交互式通信

15.3 延时确认

15.4 Nagle 算法

15.4.1 延时ACK与Nagle算法结合

15.4.2 禁用Nagle算法

15.5 流量控制与窗口管理

15.5.1 滑动窗口

15.5.2 零窗口与TCP持续计时器

15.5.3 糊涂窗口综合征

15.5.4 大容量缓存与自动调优

15.6 紧急机制

15.7与窗口管理相关的攻击

15.8总结


15.1 引言

两类TCP传输:

        交互式传输:

                单个报文小,如ssh,网络游戏中账号信息,鼠标操作等信息。

        批量传输:

                即大量数据传输。如文件共享下载,web访问。

                需流量控制,防止接收端溢出。

15.2 交互式通信

网络中大部分是大批量传输,少部分是交互式传输。

ssh是典型交互式数据。

        特点:小包。

ssh每个输入一个字符会生成4个TCP数据段:

        1. 客户端指令输入

        2. 服务器ACK

        3. 服务器执行结果

        4. 客户端ACK

其中2,3可合并一起发送,即ACK报文携带回显数据,这叫延迟ACK。

TCP段PSH标志含义:

        表示发送端没有其他数据需要传输。而接收端收到数据后应立即传递给应用层。

因为SSH客户端产生的都是短小信息,通常SSH TCP报文都带PSH标志。

15.3 延时确认

延迟ACK:

        TCP不会对收到的每个数据都回复一个ACK,而是通过累积ACK后将延迟的ACK和后续需要传的数据结合发送。

        常用于批量数据传输中。

好处:减少ACK数目,减轻网络负载。

而快速ACK,即每个报文都会回复一个ACK。

15.4 Nagle 算法

SSH客户端一个单击动作会产生四个TCP报文,其中包含TCP头,IP头等开销,代价很高,会加重广域网阻塞。

        解决方法:Nagle算法

Nagle翻译:突然

Nagle原理:

        若发送端没有收到所有数据的ACK时,不发送小报文。直到所有在传数据收到ACK,在这个等待期间会整合多个小数据,通过一个更大报文发送。

        所以ACK返回越快,数据发送越快。

优点:在高延迟网络中可整合小数据,减少小包数目。

缺点:增加了时延。

Nagle算法适用场景:

        频繁传输小数据块,并延迟不敏感。

15.4.1 延时ACK与Nagle算法结合

延时ACK:延迟发送ACK,用于减少ACK包的数量,降低网络开销。

Nagle算法:等待收到所有已发送数据的ACK后,期间合并小包成大包再发送数据。

所以可知,两者结合使用导致短暂死锁。

所以如果SSH服务器开启了延迟ACK功能,客户端最好禁用Nagle。

15.4.2 禁用Nagle算法

Nagle算法增加了时延,对实时应用不适合。

        如SSH,实时网络游戏。

内核协议栈禁用Nagle:

        net.ipv4.tcp_no_delay = 1

应用程序禁用:

        设置socket TCP_NODELAY选项

        setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flag, sizeof(int))

15.5 流量控制与窗口管理

每个TCP报文段包含:序列号,ACK号,窗口大小。

        ACK号:下一次期待收到的报文序列号,说明之前的数据已全部接收。

        窗口大小:向对方指示,自己的接收缓冲区还剩多少空间。

15.5.1 滑动窗口

每对TCP连接的两端都维护一个发送窗口和接收窗口。

        其中发送窗口大小由对端的接收窗口通告。

在没收到数据的ACK情况下,最多可发送的数据量就是发送窗口大小。

滑动窗口作用:

        优化网络利用率:

                滑动窗口允许发送方连续发送多个数据段而不必等待每个数据段ACK。提高网络利用率。

        避免拥塞:

                发送方根据接收方通告的窗口大小来控制发送量,避免发送过快而引起拥塞。

发送窗口:

一旦收到已发送数据的ACK后,就移动窗口,可继续发送更多数据。

接收窗口:

把接收窗口值给通告给发送方。

        收到数据的序列号小于左边界RCV.NXT,就是重复报文,丢弃数据。

        收到数据的序列号大于右左边界RCV.NXT+RCV.WND,超出处理范围,丢弃数据。

15.5.2 零窗口与TCP持续计时器

TCP通过接收端的窗口通告实现流量控制。指示接收端缓冲区可接收数量。

通告的接收窗口为0时,可阻止对方发送。

接收端缓冲区重新有可用空间时,可传输一个窗口更新给发送端。该窗口更新是一个纯ACK,不包含数据。

问题:

        如果接收端的窗口更新报文丢失,而发送方需要等到窗口更新报文才可继续发送。造成死锁。

解决方法:

        周期向接收端查询窗口值,即发送窗口探测,接收端回复一个ACK报文,其中包含窗口大小。

TCP报文是纯ACK,则不会重传ACK。

TCP报文不是纯ACK,会重传ACK和数据。

15.5.3 糊涂窗口综合征

糊涂窗口综合征SWS

出现原因有:

        接收端没等到窗口变大就通告,导致通告的窗口小。

        发送端没等到将小数据合成更大报文就方法,导致发送数据小。

坏处:

        传输的TCP数据很小。传输效率低。

解决方法:

        接收端不通告小窗口值。

        发送端不发送小报文段,由Nagle控制如何发送。

15.5.4 大容量缓存与自动调优

不必提前设置一个过大发送/接收缓存。而是根据待传数据大小,不断估算缓存大小,不断通告窗口大小。

        即窗口自动调优。

如何设置窗口的自动调优范围:

        接收窗口:

                net.ipv4.tcp_rmem= 4096 87380 174760

        发送窗口:

        net.ipv4.tcp_wmem= 4096 87380 174760

上述三个值分别是最小值,默认值,最大值。

最小值:

        应用程序设置发送缓冲区小于最小值时,内核自动扩大到最小值,如

默认值:

        应用程序未指定发送缓冲区大小时,内核会使用这个默认值。

最大值:

        应用程序不能设置发送缓冲区的大小超过最大值。

自动调优:

        当接收端根据接收缓存区剩余大小,动态发送窗口更新报文给发送端,控制发送端发送速率。

若TCP的接收缓存区太小,会严重限制TCP吞吐量。

小结:接收窗口和发送窗口值会根据网络环境和系统配置而动态调整,通常范围为几KB到几MB。

15.6 紧急机制

TCP URG标志:

        指示该TCP报文包含紧急数据。

MSG_OOB标志可发送接收带外数据。

        带外数据:使用带外(额外)通道来传输数据,可不受滑动窗口控制,实现传输紧急数据。

MSG_OOB使用方法如:

        send(socket_fd, buff, buff_len, MSG_OOB);

        recv(socket_fd, buffer, MAX_BUFFER_SIZE, MSG_OOB);

MSG_OOB数据比普通数据有更高优先级。

15.7与窗口管理相关的攻击

通告非常小的窗口,让发送方缓慢发送,并保持忙碌发送,耗尽资源。

15.8总结

延迟ACK:

        使用场景:交互式通信中,当接收方收到数据后,延迟回复ACK,等到有数据发送时再一起携带ACK发送。

        优点:减少包数量。

        缺点:延时增大。

Nagle算法:

        使用场景:广域网中RTT较大的环境中,采用Nagle算法,可以合并多个小数据包成一个,再发送。

        优点:减少包数量,降低传输开销。

        缺点:延时增大。

延迟ACK和Nagle算法会短暂死锁,有的会禁用Nagle算法。

        通常延时不敏感的交互式应用可使用Nagle。

当接收端的接收缓存为空,会通告窗口为0。此时发送端会停止发送,并周期发送窗口探测,直到通告不为0。

糊涂窗口综合症:

        接收端通告了小窗口,发送端立即发送小数据,导致网络太多小数据。

        解决方法:

                接收端不通告小窗口。

                发送端不发送小数据。

The End
微信