前面一节咱们介绍完了TCP协议,这部分,将要介绍,TCP是如何实现可靠传输的。

TCP的可靠传输

1.滑动窗口

上一节我们介绍TCP报文段头部的时候说得到,"窗口"这个部分,"窗口"的内容就是发送/接收的数据的字节总量(窗口是以字节为单位)。

发送方A有发送窗口,接收方B有接收窗口。头部的"窗口"要配合"确认号"才能确定,要发送哪些数据和具体接收哪些数据。

现假定A收到了B发来的确认报文段中,其中窗口是20(字节),而确认号是31(这表明B期望收到的下一个序号是31,而序号31之前的数据已经收到了),A就构造出自己的发送窗口,如下图:

我们现在来讨论一下A的发送窗口:

在没有收到B确认的情况下,A可以连续把窗口内的数据都发送出去。凡是发送过的数据,会暂时保留一份副本,以便超时重传时使用。

发送窗口的位置由窗口前沿和窗口后沿的位置共同决定。

后沿: 上图中后沿的后面部分(左边)表示已经发送并且收到了确认。这些数据不在保留副本。

后沿变化的情况有两种:不动(没有收到新的确认号(>31))和前移(收到了新的确认号)。后沿是不会向后移动的,因为不能撤销掉已收到的确认。

前沿: 上图中前沿的前面部分(右边)表示不允许发送的数据。

前沿变化情况有三种:

向前移动: 收到新的确认后(>31)的通常情况

不动: 没有收到确认;收到了新的确认号(35),但窗口值变小了变成了15,那前沿的位置还是在50那。

收缩:窗口值变得更小。如上面新的确认号是35,但窗口值变成了10,那前沿的位置就到了45的位置。不过TCP的标准强烈不赞成这样做。

后沿前沿的移动,正好就把窗口滑动的特点展示出来了。

下面我们再通过举例子,再详细介绍滑动窗口的特点

假定A发送了窗口中序号为31~41的数据(黑色小方框表示),表示已发送但未收到确认。而42~50号的数据是允许发送但尚未发送的。如下图。

上图中,要描述发送窗口的状态需要三个指针:P1,P2,P3。而小于P1的是已经发到并且收到确认的部分,大于P3是不允许发送的部分。

P3 - P1 = A的发送窗口(通知窗口)

P2 - P1 = 已发送但尚未收到确认的字节数。

P3 - P2 = 允许发送但尚未发送的字节数(可用窗口或有效窗口)

再说一下B的接收窗口。先看下图。

B接收窗口内的序号(31~50)是允许接收的。在上图中,32,33的被接收到了,而31的数据没有收到(也许丢失,也许滞留在网络中)。而B只能将按顺序收到的数据中,将最高号作为确认号发出。由于31号还没有收到,所以B发送的确认报文仍然是31,而不是32或33。

现在假设B收到了31号数据,并把31~33的数据交给应用程序,然后B会删除这些数据。接着把接收窗口向前移动3个序号,同时给A发送确认号34,窗口只20。

此时A、B窗口移动后的图如下:

A收到了收到了B发送的34号确认号,20的窗口值,所以P1移至34,P3移至53。但P2指针没有动。

而我们可以看到B还接收到了37、38、40。但这些数据没有按序到达,所以只能先暂存在接收窗口中。

然后,A再继续发送完序号42~53的数据后,指针P2向前移动和P3重合。如下图:

窗口内的序号已经用完。但还没有收到B的确认。如果过了一段时间A还没有收到确认,就只能超时重传这部分数据,直到B收到确认位置。

如果A收到确认号落在发送窗口内,那么A可以使窗口向前滑动,发送新的数据。

2. 发送/接收缓存

发送方的应用进程把字节流写入TCP的发送缓存;接收方的应用进程从TCP的接收缓存中读取字节流。下图画出了TCP缓存和窗口之间的关系:

我们先来看(a)图:

可以看到数据量大小是发送缓存>应用程序>发送窗口。

发送缓存用来暂时存放:

1: 应用程序传给TCP准备发送的数据。

2: TCP已经发送但未收到确认的数据。

应用程序必须控制写入缓存的速率,不能太快,否则发送缓存就是会没有存放数据的空间。(I/Obuffer)

再看一下(b)图:

接收缓存用来暂时存放:

1: 按序到达的、但尚未被接收应用程序读取的数据

2: 未按序到达的数据

如果收到的分组被检测出有差错,则要丢弃。如果应用程序来不及读取收到的数据,接收缓存最终就会被填满,使接收窗口减小到0。反之,如果应用程序能够及时从接收缓存中读取收到的数据,接收窗口就可以增大,但不能超过接收缓存的大小。(b)中还指出了,下一个期望收到的字节号,这个字节号也就是接收方给发送方的报文段的首部中的确认号。

经过讨论,可以强调3点:

1. A的发送窗口是根据B的接收窗口来设置的。

2. TCP对不按序到达的数据会先临时存放在接收窗口中,等到缺少字节收到后,再上交付到应用程序。

3. TCP要求接收方必须有积累确认的功能,这样可以减小传输开销。接收方可以在合适的时候发送确认,也可以在自己有数据要发送时把确认信息顺便捎带上。

3. 超时重传选择

3.1超时重传时间设置

如果超时时间设置的太短,就会引起报文段不必要的重传,增大网络负荷;如果设置的太长,又增加了网络的空闲时间,降低了传输效率。所以超时重传时间设置应该是动态变化的。

RTT(报文段的往返时间): 一个报文段发出的时间,到收到确认的时间。

RTTs(加权平均往返时间或平滑往返时间): 根据RTT计算出来的,超时重传时间。

新的RTTs = (1-α)*(旧的RTTs) + α*(新的RTT样本)。新的RTT即动态变化的重传时间。

RFC2988推荐的α值为1/8。用这种方法得出的加权平均往返时间RTTs就比测量出的RTT值更加平滑。

3.2超时计时器的设置

RTO(超时计时器设置的超时重传时间),应该略大于RTTs。RTO就是真正用来计算超时重传的时间设置。

RTO=RTTs + 4 * RTTd

RTTd是RTT的偏差的加权平均值。当第一次测量时,RTTd值为测量到的RTT值的一半,往后的测量中,RTTd的计算公式如下:

新的RTTd = (1-β) * (旧的RTTd) + β * |RTTs - 新的RTT样本|

β的推荐值是1/4。

3.3Karn算法

重传后,如何判定此确认报文段是对先发送的报文段的确认,还是对后来重传报文段的确认?重传报文段和原来的报文段完全一样,因此源主机在收到确认后无法作出正确的判断,而RTTs的值对正确的判断影响很大。

Karn提出了一个算法:在计算RTTs时,只要报文段重传了,就不采用重传报文段的往返时间样本(即上面公式中新的RTT)。这样得出的RTTs和RTO就比较准确。

但有个问题,就是超时重传时间无法更新。于是修正后的Karn算法是:报文段每重传一次,就把超时重传时间RTO增加大一些。典型做法是取新的重传时间为2倍的旧的重传时间。当不发生重传时,才根据上面RTO的公式计算超时重传时间。

选择确认SACK

在第一章介绍报文段头部选项的时候有介绍SACK的作用:只传送缺少的数据,不重传已经正确到达接收方的数据。

然而SACK文档没有指明发送方应当怎样响应SACK。因此大多数的实现所有未被确认的数据块。

TCP学习总结(二)的更多相关文章

  1. 网络编程基础之TCP学习(二)编程案例

    TCP网络编程流程如下: 实现功能:服务器端与客户端成功通讯后返回get! 服务器端程序 #include <netdb.h> #include <sys/socket.h> ...

  2. TCP学习之二:客户端与服务端的连接

    主要参考张子阳大神的博客:http://www.cnblogs.com/JimmyZhang/category/101698.html TcpClient是对Socket的封装 一个TcpClient ...

  3. CentOS 7 学习(二) 配置Nginx反向代理

    CentOS 7 学习(二) 配置Nginx反向代理 Nginx可以通过php-fpm来运行PHP程序,也可以转向apache,让apache调用php程序来运行. 不过对于Nginx来说,其反向代理 ...

  4. 《Spring Cloud》学习(二) 负载均衡!

    第二章 负载均衡 负载均衡是对系统的高可用.网络压力的缓解和处理能力扩容的重要手段之一.Spring Cloud Ribbon是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于Netfli ...

  5. Netty 学习(二):服务端与客户端通信

    Netty 学习(二):服务端与客户端通信 作者: Grey 原文地址: 博客园:Netty 学习(二):服务端与客户端通信 CSDN:Netty 学习(二):服务端与客户端通信 说明 Netty 中 ...

  6. crawler4j 学习(二)

    crawler4j 学习(二) 实现控制器类以制定抓取的种子(seed).中间数据存储的文件夹.并发线程的数目: public class Controller { public static voi ...

  7. 从零开始学习jQuery (二) 万能的选择器

    本系列文章导航 从零开始学习jQuery (二) 万能的选择器 一.摘要 本章讲解jQuery最重要的选择器部分的知识. 有了jQuery的选择器我们几乎可以获取页面上任意的一个或一组对象, 可以明显 ...

  8. Android Animation学习(二) ApiDemos解析:基本Animators使用

    Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...

  9. AspectJ基础学习之二搭建环境(转载)

    AspectJ基础学习之二搭建环境(转载) 一.下载Aspectj以及AJDT 上一章已经列出了他的官方网站,自己上去download吧.AJDT是一个eclipse插件,开发aspectj必装,他可 ...

随机推荐

  1. 无法添加注解@Resource

    Spring项目中缺少javax.annotation包的依赖

  2. ps使用经验

  3. 《R语言入门与实践》第三章:R 对象

    在这一章,包含的内容有: R 的数据类型 属性 类(特殊的属性) Ruby 的数据结构 R 数据类型 R 可以识别六种类型的数据类型,分别是: double integer character log ...

  4. LRU算法的Java实现

    LRU全称是Least Recently Used,即最近最久未使用的意思. LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已 ...

  5. jquary高级和ajax

    jquary高级: 1.动画 1.三种方式显示与隐藏元素 1.默认显示和隐藏的方式 1.show([speed],[easing],[fn]):显示 [speed],[easing],[fn] spe ...

  6. android -------- 沉浸式状态栏和沉浸式导航栏(ImmersionBar)

    android 4.4以上沉浸式状态栏和沉浸式导航栏管理,包括状态栏字体颜色,适用于Activity.Fragment.DialogFragment.Dialog,并且适配刘海屏,适配软键盘弹出等问题 ...

  7. NodeJS基础(二)

    一.动态获取文件路径 var fs = require('fs') var path = require('path') // 一般在开发命令行工具的时候,这个设计是必须有用的一个特性 // npm ...

  8. SAP基础:定位点运算

    先看一下下面简单的代码: REPORT zlytest003. ) VALUE '21.00'. ) . b = a. WRITE b. 运行结果是: 这时候到程序属性页面: 修改固定点算术为空. 保 ...

  9. checkbox属性获取

    checked属性获取不能用attr,要用prop

  10. linux下用户操作

    在linux中添加ftp用,并设置相应的权限,操作步骤如下: 1.环境:ftp为vsftp.被限制用户名为test.被限制路径为/home/test. 2.建用户:在root用户下: useradd  ...