zoukankan      html  css  js  c++  java
  • 运输层:TCP 流量控制

    禁止码迷,布布扣,豌豆代理,码农教程,爱码网等第三方爬虫网站爬取!

    流量控制

    TCP 连接的每一侧主机都为连接设置了接收缓存,当 TCP 连接收到正确、按序的字节以后,就会将数据存入缓存。在实际情况下,接收方应用可能会忙于其他事务,因此无法及时读取缓存中的数据。若主机上某应用读取数据时相对较慢,而发送方发送的报文段太多、太快,发送的数据就很可能使连接的接收缓存溢出

    接收窗口

    TCP 为应用程序提供了流量控制服务,以此消除发送方使接收方接收缓存溢出的可能性。因此流量控制是一个速度匹配服务,发送方的发送速率应当尽可能接收方应用程序的读取速率相匹配。TCP 通过让发送方维护一个接收窗口(rwnd)的变量,用于指示接收方还有多少可用的缓存空间。

    rwnd 计算

    rwnd 是一个动态数值,假设主机 A 向主机 B 发送一个大文件,定义以下 3 个变量:

    • RcvBuffer:主机 B 接收缓存的大小;
    • LastByteRead:主机 B 上的应用进程从缓存中读出的数据流的最后一个字节编号;
    • LastByteRcvd:从网络中到达并已经放入主机 B 接收缓存中的数据流的最后一个字节编号。

    由于 TCP 不允许出现接收缓存溢出,因此下列式子必须成立:

    因此接收窗口 rwnd 的数值,可以使用上述式子推出:

    流量控制实现

    主机 B 通过把当前 rwnd 值放入主机 A 报文段接收窗口字段中,通知主机 A 在该链接缓存中还有多少可用空间,rwnd 初始值为 RcvBuffer。主机 A 需要跟踪以下 2 个变量:

    • LastByteSent:主机 A 已发送的字节数;
    • LastByteAcked:主机 A 收到的 ACK 中主机 B 已确认的报文段对应的字节数。

    这 2 个变量作差就是主机 A 已发送但是未被确认的数据量,因此可以退出主机 A 需要保持:

    死锁

    B 向 A 发送了 rwnd = 0 的报文段后不久,B 的接收缓存又有了一些存储空间,于是 B 向 A 发送了 rwnd = 400 的报文段。但这个报文段在传送过程中丢失了,A 一直等待收到 B 发送的非零窗口的通知,而 B 也一直等待 A 发送的数据。如果没有其他措施,这种互相等待的局面将一直延续下去,这种情况称之为死锁
    为了解决这个问题,TCP 为每一个连接设有一个持续计时器 (persistence timer),只要 TCP 连接的一方收到对方的零窗口通知,就启动该持续计时器。若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值。若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器。若窗口不是零,则死锁的僵局就可以打破了。

    发送时机

    发送机制

    发送方获取 rwnd 之后,就需要选择合适的发送时机。可以用不同的机制来控制 TCP 报文段的发送时机:

    1. TCP 维持一个等于最大报文段长度 MSS 的变量,只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去。
    2. 由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送 (push)操作。
    3. 发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去。

    尽管已经有一些方案,但是如何控制 TCP 发送报文段的时机仍然是一个较为复杂的问题。例如发送方 TCP 每次接收到 1 字节的数据后就发送,每发送 1 个字节需要形成 41 字节长的 IP 数据报。若接收方确认并回送这 1 字节,就需传送总长度为 162 字节共 4 个报文段,当带宽不富裕时效率很低。解决方法为:使用 Nagle 算法。

    Nagle算法

    若发送应用进程把要发送的数据逐个字节地送到 TCP 的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节都缓存起来。
    当发送方收到对第一个数据字符的确认后,再把发送缓存中的所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后,才继续发送下一个报文段。当到达的数据已达到发送窗口大小的一半,或已达到报文段的最大长度时,就立即发送一个报文段。

    糊涂窗口综合症

    当接收方的 TCP 缓冲区已满,接收方会向发送方发送窗口大小为 0 的报文。若此时接收方的应用进程以交互方式每次只读取 1 个字节,接收方又发送窗口大小为 1 个字节的更新报文。发送方应邀发送 1 个字节的数据(发送的 IP 数据报是 41 字节长),于是接收窗口又满了,如此循环往复使得网络效率很低。
    解决方法为,让接收方等待一段时间,使接收缓存已有足够空间容纳一个最长的报文段,或者等到接收缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发出确认报文,并向发送方通知当前的窗口大小。

    参考资料

    《计算机网络(第七版)》 谢希仁 著,电子工业出版社
    《计算机网络 自顶向下方法》 [美] James F.Kurose,Keith W.Ross 著,陈鸣 译,机械工业出版社

  • 相关阅读:
    Spring MVC 通过ajax实现前后台交互
    一些基础的东西总结一下
    如何在页面中引用自定义标签
    Linux(centos)系统下安装fastdfs安装部署步骤,问题复现 并在java中集成测试demo
    Liunx下修改JVM内存大小
    在liunx下安装配置rabbitMQ详细教程
    Oracle创建用户、角色、授权、建表
    要做小程序的订阅推送 本篇 从小程序到后端!!!
    Thymeleaf入门入门入门入门入门入门入门入门入门入门入门
    git clone 解决Permission Denied (publickey)问题
  • 原文地址:https://www.cnblogs.com/linfangnan/p/13286429.html
Copyright © 2011-2022 走看看