| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> LWIP/TCPIP糊涂窗口综合症 -> 正文阅读 |
|
[网络协议]LWIP/TCPIP糊涂窗口综合症 |
?????????TCP协议栈基于滑动窗口动态调整机制进行流量控制会导致一种被称为“糊涂窗口综合症SWS (Silly WindowSyndrome)"的状况。当TCP接收方通告了一个小窗口,并且TCP发送方立即发送数据填充该小窗口时,糊涂窗口综合症SWS (Silly WindowSyndrome)就会发生。 ????????糊涂窗口综合症能够导致网络性能严重下降。当TCP的双方都是以小窗口通告和小报文段发送来实现通信,会使TCP数据流包含很多非常小的报文段,而不是满长度的报文段;而小单元报文段中IP首部和TCP首部这些字段占了大部分空间,会导致真正有效的TCP数据却很少,因此小报文的传输浪费了网络的大量带宽,从而网络性能严重下降。 ????????糊涂窗口综合症可以由TCP连接双方中的任何一方引起。这是由于接收方可以通告一个小的窗口(而不是一直等到有大的窗口时才通告),而发送方也可以发送少量的数据(而不是等待更多的数据以便发送一个大的报文段)。为了避免SWS的发生,发送方和接收方必须设法消除这种情况。解决措施:接收方不必通告小窗口更新,而发送方不必发送小的报文段。在任何一方采取措施,都可以消除糊涂窗口综合症的发生。 ????????对于接收端的优化 ????????1. 应用程序上层读取数据后,TCP接收窗口会变大,但是接收方在小窗口更新的情况下不对发送方进行窗口通告,而是等待窗口大小满足一定的条件之后【能够接收一个最大报文段,或者增加接收缓冲区的一半】,再来发送窗口通告,这样就不会产生小报文。我们看看lwip对这一优化的实现
????????2. 推迟确认(Delay ACK)的方法避免SWS,这时的做法是当接收窗口未达到满足要求的通告大小时,TCP推迟确认的发送(数据发送也会捎带ack)。推迟确认需要把握好推迟的时间,否则可能导致接收方因为等不到确认而重传报文段,TCP标准中规定,TCP实现对确认最多只能推迟500ms。同时,为了不影响发送方的RTT估计,接收方最好能保证每隔一个报文段进行一次确认。在LwIP作为接收方时,它采用了推迟确认的方法来避免SWS的发生。在控制玦的flags字段的TF_ACK_DELAY位表示了当前有ACK被延迟,我们来看看宏tcp_ack的定义。
????????tcp_ack被调用时,会根据flags中TF_ACK_DELAY和TF_ACK_NOW两位的状况来决定是否发送ACK。若控制块上有ACK被延迟,则在内核的250ms周期性函数tcp_fasttmr中,会在该控制块上立即发送ACK。 ????????对于发送端的优化 ????????1. 对于从应用程序中接收到的第一块数据【没有任何等待ACK的包】,立即发送,一个字节的数据也需要发送出去。 ? ? ? ? 2.推迟小报文段的发送,TCP尽量组织后续数据成为一个大的报文段发送。 ????????那么一个小报文段在被发送出去之前能够推迟多久呢? TCP也无法预计应用程序发送数据的时间和规律,等待时间太久会导致应用程序的延时过大,而太短会使报文段依旧很小,浪费网络带宽。通常发送端使用了一种自适应的方法,利用确认的到来去触发其余分组的传输。 ????????在连接上仍有己传输数据还未被确认的情况下,如果发送应用程序又产生了新的数据发送,那么TCP会照常把这些数据放入到输出缓冲中,但此时并不立即发送报文段,而是等待这些数据能够填满一个最大长度的报文段之后,才把缓冲区中的数据组织成一个报文段发送出去,这种策略适用于任何情况,包括推操作在内。这就是Nagle算法。来看看在报文段发送时,LwIP是如何避免糊涂窗口的,报文段的发送在函数tcp_output中完成。
? ? ? ? while语句中的循环条件,它要求待发送的所有报文段数据都必须在有效发送窗口内,这样即使对方通告了一个很小的窗口,大报文段也不会被发送出去。对于其他情况,则可以利用Nagle算法来判断是否发送报文段。注意,如果flags的TF_NAGLEMEMERR和TF_FIN标志置位,Nagle算法失效,即任何报文都不会被Nagle算法阻止。TF_NAGLEMEMERR可以理解为内存错误,它是在tcp_enqueue函数组装报文时,出现可用发送缓存空间不足时置位的,当这种情况发生时,己经组装好的报文段需要尽快被发送,为后续发送预留出空间;TF_FIN标志置位时说明上层应用发出了关闭连接命令,此时也应尽快发送连接上的报文段。 Nagle算法是通过宏tcp do output nagle来实现的,代码如下:
????????Nagle算法有效阻止报文段发送的情况具体是:unacked队列不为空,且Nagle算法已使能(TF_NODELAY未置位)、控制块不处于快速重传状态(TF_INFR未置位),且unsent发送队列上的报文段少于两个,且第一个报文段的长度小于最大报文段长度时。当上述条件都成立时,tcp do output nagle取值为0,在tcp_output函数调用时没有报文段被发送。而在tcp_enqueue每次组装报文段的过程中,它都会试图将新报文段和未发送队列上的前一个报文段进行合并。很多情况下需要禁止Nagle算法,这可以直接通过设置控制块flags字段中的TF_NODELAY标志来实现。 ? ? ? ? 我们在做网络开发中,会经常使用协议来进行数据数据交互,我们经常会遇到粘包现象,造成这个原因有两个:1.接收端的粘包,?如果接收端来不及从socket缓冲区中读取数据, 那么就会造成粘包;2.接收端的粘包, 则主要归因于TCP nagle算法。 ? ? ? ? 对于粘包,我们可以在发送端禁止nagle算法,接收快速从socket中读取数据,但是这也并不一定能解决粘包问题,定义在协议数据传输中的数据,我们可以使用单字节数据解析来解决粘包问题。例如:
????????文档内容参考了TCPIP详解、老衲五木(朱升林)的微博。 |
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 19:35:41- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |