TCP/IP协议(五、tcp滑动窗口)_windows下默认的tcp窗口值是多少-程序员宅基地

技术标签: tcp  # TCP/IP协议  tcp滑动窗口  滑动窗口  

终于来到了TCP的滑动窗口,本来计算第二节就讲滑动窗口,但是每次都是计划赶不上变化,一推再推,所以来到了第5节,不过也不晚,趁早搞懂TCP/IP还是很有用的。

5.1 延时ACK

TCP的一个重点知识点延时ACK,但是还是从交互式通信讲起。

5.1.1 交互式通信

"交互式"TCP连接是指,该连接需要在客户端和服务器之间传输用户输入信息,如按键操作、短消息、操作杆或鼠标的动作等。这些包都是比较小的包,如果没一个很小的包都要组成一个报文来传输,那么传输协议需要耗费很高的代价,因为每个交换分组中包含的有效负载字节较少。反之,报文段较大怎会引入更大的延时。对延迟敏感类应用(如在线游戏,协同工具等)造成负面影响。因此需要找到一个折中的方法、

交互式通信其实比较简单,就是客户端获取用户输入信息,然后将其传给服务器。服务器对命令进行解析并生成相应返回给客户端。有点像一请求一应答模式。

但是让我也奇怪的是,每个交互按键通常都会生成一个单独的数据包。也就是说,每个按键都是独立传输的(每次一个字符而非每次一行,说实话,我不是看到TCP详解中说,我也很纳闷,这么会这样设计)。

像我们平时使用的ssh和服务器通信的话,服务器需要对输入字符做出回显。所以这个过程应该是这样子的:
在这里插入图片描述
如果将数据字节确认和数据字节回显合并的话,会不会高效一点,这种方法就是我们下面说的延时确认。

5.1.2 延时确认

在许多情况下,TCP并不对每个到来的数据包都返回ACK,利用TCP的累积ACK字段(这个我也不是很清楚,清楚的可以在下面留言)就能实现这个功能。累积确认可以允许TCP延迟一段时间发送ACK,以便将ACK和相同方向上需要传的数据结合发送。TCP实现ACK延时的时延应小于500ms。实践中时延最大取200ms.

采用延时ACK的方法会减少ACK传输的数目,可以一定程度地减轻网络负载。

用法:
通常TCP在某些情况下使用延时ACK的方法,但时延不会很长。
在大数据包传输中只要采用的是拥塞控制和延时ACK。
在小数据包传输中,如交互式应用,需要采用另外的算法。(就是下面说的Nagle算法)

5.1.3 Nagle算法

从前面的讲解可以看出,ssh连接中,通常单次击键就会引发数据流的传输,这些小包的数据量不到,但是需要带上整个TCP/ip头,所以会造成很高的网络传输代价。所以John提出了一种简单有效的解决方法,现在成其为Nagle算法。下面讲解一下这个算法的含义;

  • 当一个TCP连接中有在传数据(即那些已发送但还为经确认的数据),小的报文段(长度小于SMSS)就不能被发送,直到所有的再传数据都收到ACK
  • 在收到ACK之后,TCP需要收集这些小数据,讲起整合到一个报文段中发送。

举个栗子:
首先观察禁用Nagle算法的情况:
在这里插入图片描述
这一个图是从tcp/ip详解中截取出来的,我们先看下面,F1键我是输入了3个字符,在禁用Nagle算法的时候,是每一个字符单独发送,所以我们看到的是3个单独的包,在服务器回复ack的时候,出现了丢包,客户端没有接受到ack2,服务器会重传一个ack2.客户端就接收到后,就回复了ack6,说明6之前的包都接收好了,这个在滑动窗口有说过。

然后第二个按键也是3个字符,这样就不说了,都是一样的。

通过这个例子我们明显感觉到,小包太多了,这样很浪费网络资源,所以就提出了Nagle算法。

下面我们来看看开启了Nagle算法之后的效果:
在这里插入图片描述
这就是开启Nagle算法的过程,是不是中间没有小包的存在了,通信也简洁了。

但是这样子会带来一个问题:
有没有发现每次发送一个请求报文之后,回复的ACK都是200ms左右,这就是延时ACK决定的,服务器收到了一个请求报文,会开启一个定时器,等待200ms,如果这时候再次接受到客户端的请求,会两个ack做为一个返回,但是犹豫客户端使用的是Nagle算法,他会一直等待ACK才会再次发送请求,这里就会形成一个死锁,不过这个死锁不是一直的,直到延时ack超时之后,就会给客户端发送ack了,客户端就会可以再次发送了,这也是看到图发现一个请求都是等待200ms左右才有回应。

总结:
从前面的例子可以看出,在有些情况下并不适用Nagle算法。

典型的包括那些要求时延尽量小的应用,如远程控制中鼠标或按键操作需要及时送达以得到快键的反馈。
还有多人网络游戏,人物的动作需要及时地传送以确保不影响游戏进程。

禁用Nagle算法也简单,可以设置TCP_NODELAY选项即可。

5.2 滑动窗口

TCP是传输控制协议,socket:流式套接字,顺序。
我们应用层都是用socket来接收的,那我们接收的数据怎么保证顺序性呢?
我们要知道网络中传输各种情况都有可能发生,前一个包选择了一个路由路径,后一个包就可能选择另外的一个路由,可能会导致后面的包比前面的包提前到大。

所以我们接下来说的TCP协议栈中使用滑动窗口这种机制来确保接收数据的顺序性。

5.2.1 发送窗口

TCP连接的每一端斗可收发数据。连接的收发数据量是通过一组窗口结构来维护的。每个TCP活动连接的两端都维护一个发送窗口结构和接收窗口结构。

接下来先看看发送窗口的结构:
在这里插入图片描述
发送窗口有四个部分,第一个部分已发送并已经确认,就是接收端已经回复了ACK,第二个部分已经发送但未经确认,这一部分可能在传输中,也可能已经被接收了,但是由于没有到延时ack的时间,所以还没确认,第三部分即将发送,将要发送的数据,其中第二部分和第三部分是由接收端通告的窗口称为提供窗口,是接收到3字节之后,回复ack中,顺带了一个6字节大小的窗口,在之前TCP初识的这篇,有介绍过窗口的字段。(因为窗口字节是4字节,最大为65535,所以在选项字节中有一个窗口因子,是扩展了窗口大小的)。最后一部分,是不能发送的,接收端就是依靠这个窗口来控制发送端的速率,就是控制只能发送多少字节,后面的不能发送,等到接收到已经发送但未确定的数据,并返回ACK之后,发送端的窗口才继续往右移。所以这个叫做滑动窗口。

注意:TCP不支持窗口右边界左移。

每个TCP报文段都包含ACK号和窗口通告信息,TCP发送端可以据此调节窗口结构。窗口左边界不能左移,因为它控制的是已确认的ACK号,具有累积性,不能返回。当得到的ACK号增大而窗口大小保持不变时(通常如此)。我们就说窗口向前“滑动”。若随着ACK号增大窗口却减小,则左右边界距离减小。当左右边界相等时,称之为**“零窗口”**。此时发送发送端不能再发送新数据。这种情况下,TCP发送端开始探测(probe)对方窗口,伺机增大提供窗口。

5.2.2 接收窗口

接收端也维护了一个窗口结构,但比发送端窗口简单。
在这里插入图片描述
接收窗口包含了3个部分,第一部分已接收并确认的数据,第二部分,接收后将会保存的数据,该窗口可以保证其接收数据的正确性,特别是,避免存储重复的已接收和确认数据,也可以避免存储不应该接收的数据(超过发送方右窗口边界的数据)、第三部分就是不能接收的数据。

注意:由于TCP的累积ACK结构,只有当到达数据序列号等于左边界时,数据才不会被丢弃,窗口才能向前滑动。对选择确认TCP来说,使用SACK选项,窗口内的其他报文段也可以被接收确认,但只有在接收到等于左边界的序列号数据时,窗口才能前移。

5.2.3 零窗口与TCP持续计时器

我们在前面了解到,TCP是通过接收端的通告窗口来实现流量控制的。通告窗口指示了接收端可接收的数据量。当窗口值变为0时,可以有效的阻止发送端继续发送,直到窗口大小恢复为非零值。

当接收端重新获得可用空间时,会给发送端传输一个窗口更新,告知发送端可以继续发送数据了,但是这样的窗口更新只是一个纯ACK,没有包含数据,所以如果出现了丢失,就不会发送重传。这样子的话,发送和接收两端都处于等待状态,会形成一个死锁。

为防止这种死锁发生,发送端会采用一个持续计时器间歇性的查询接收端,看其窗口是否已经增长。持续计时器会触发窗口探测的传输,强制要求接受端返回ACK(其中包含窗口信息),随后以指数时间间隔发送。

5.2.4 糊涂窗口综合征

看书看的比较糊涂,所以百度了一下,有一篇写的还可以:TCP-IP详解:糊涂窗口综合症(Silly Window syndrome)

这里就抄抄一下原因:
这个问题可以归结为小包的问题,就是由于发送端和接收端上的处理不一致,导致网络上产生很多的小包,之前也介绍过避免网络上产生过多小包的措施,比如Nagle算法。在滑动窗口机制下,如果发送端和接收端速率很不一致,也会产生这种比较犯傻的状态:发送方发送的数据,只要一个大大的头部,携带数据很少。

对于接收端来讲,如果接收很慢,一次接收1个字节或者几个字节,这个时候接收端 缓冲区很快就会被填满,然后窗口通告为0字节,这个时候发送端停止发送,应用程序收上去1个字节后,发出窗口通告为1字节,发送方收到通告之后,发出1个字节的数据,这样周而复始,传输效率会非常低。

同时如果发送端程序一次发送一个字节,虽然窗口足够大,但是发送仍是一个字节一个字节的传输,效率很低

解决方案:
接收端:

  • 不应该通告小的窗口值。(在窗口可增至一个全长的报文段MSS或者接收端缓存空间的一遍之前,不能通告比当前窗口更大的窗口)。
  • 延时ACK,和累积ACK。

发送端:

  • 不应该发送小的报文,而且需由nagle算法控制何时发送。

为了避免SWS问题,满足下面的条件才能传输报文段。

  • 全长(发送MSS字节)的报文段可以发送
  • 数据长度≥接收端通告过的最大窗口值的一半,可以发送
  • 某一个ACK不是目前期盼的(需要重发)
  • 禁用Nagle算法

现在的linux内核中的TCP算法是支持窗口自动调优的,以后有空再分析。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/C1033177205/article/details/108230013

智能推荐

while循环&CPU占用率高问题深入分析与解决方案_main函数使用while(1)循环cpu占用99-程序员宅基地

文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。​​​​​​while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99

【无标题】jetbrains idea shift f6不生效_idea shift +f6快捷键不生效-程序员宅基地

文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效

node.js学习笔记之Node中的核心模块_node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是-程序员宅基地

文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是

数学建模【SPSS 下载-安装、方差分析与回归分析的SPSS实现(软件概述、方差分析、回归分析)】_化工数学模型数据回归软件-程序员宅基地

文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件

利用hutool实现邮件发送功能_hutool发送邮件-程序员宅基地

文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件

docker安装elasticsearch,elasticsearch-head,kibana,ik分词器_docker安装kibana连接elasticsearch并且elasticsearch有密码-程序员宅基地

文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码

随便推点

Python 攻克移动开发失败!_beeware-程序员宅基地

文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware

Swift4.0_Timer 的基本使用_swift timer 暂停-程序员宅基地

文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停

元素三大等待-程序员宅基地

文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待

Java软件工程师职位分析_java岗位分析-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析

Java:Unreachable code的解决方法_java unreachable code-程序员宅基地

文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code

标签data-*自定义属性值和根据data属性值查找对应标签_如何根据data-*属性获取对应的标签对象-程序员宅基地

文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象

推荐文章

热门文章

相关标签