tcp下载窗口太小的问题_tcp所有定时器

tcp协议中所有定时器。超时一词在软件领域用途非常广泛,是解决的很多问题利器。TCP设计精髓在于他自我管理的状态机,而要想状态机正常运行,超时必不可少,如connect flood攻击。

建立连接定时器

开始

TCP属于可靠连接,需要经历三次握手。

其中No对应列表的序 .

环境查看

总时间为63s,这个时间还是难以忍受的,想想如果一个食堂因为你一个人等了1分多钟,估计你会被打shi

  • 抓包: tcpdump -i lo ‘tcp[tcpflags] = tcp-syn’

在这里我们重点分析发送窗口,其原理是一个发送窗口,其中包括两部分内容:已发送但未确认和可以发送但还未发送的。

超时重传

  1. 超时重传原理
    超时重传是TCP保持可靠性中不可缺少的一项。其原理是发送一个数据后就开启一个计时器,在一定时间内如果没有得到ACK分节(如上图Window Alreadly Sent 14bytes),则发送端重新发送数据 文,直到数据全部发送成功为止,此时会重置RTO。
    当然需要注意的是,此份数据因为保存在内核,而且保存完成路由的信息,所以在重传时不会涉及到数据拷贝(应用进程到内核的双向复制),也不需要上文切换,所以只需要将数据从内核搬到 卡,重新发送即可。
  2. Linux下有两个重要的内核参数和TCP超时有关:

tcp_retries1:表示指定在底层IP接管之前(也就是不需要 络层参与)TCP最少执行的重传次数,默认值为3;
tcp_retries1:表示连接放弃前TCP最多执行的重传次数,默认值为15(一般对应13-30分钟)。

坚持定时器(persist timer)

开始

TCP提供流量控制机制,其原理:TCP总是告知对端在任何时刻他一次能够从对端接受多少字节的数据,这也被为通告窗口(Advertised Window)。在任何时刻,该窗口指出接受缓冲区当前可用的空间量(可以使用netstat -lpn查看),从而确保发送端发送的数据不会使接收端缓冲区溢出。

  • 当前接受和发送缓冲区大小

实验与分析

  • 该窗口时刻动态变化的,当接受到来自发送端的数据时,窗口大小就减小;而接受端读取数据后,窗口会变大。通过窗口大小可能是0,此时会通知发送端不要在发送数据,那么问题来了,客户端什么时候再继续发送数据呢傻等着吗显然是:No。
  • 当然,TCP规范中约定,即使对端为0窗口模式,但依旧接受以下几种 文:零窗口探测 文、确认 文和携带紧急数据的 文段。因此,为解决这种死锁问题,此时需要一个坚持定时器。TCP为每个连接设置一个坚持定时器,只要TCP连接一方收到对方的0窗口通知,就启用该定时器。若定时器到期,就发送一个零窗口探测 文(仅携带一个字节的数据),对方在ACK这个探测 文时设置当前的窗口大小。
  • 实验
    • 服务端代码(centos6.7)

    • 结果

TCP_KEEPDILE:设置连接上如果没有数据发送的话,多久后发送keepalive探测分组,单位是秒
TCP_KEEPINTVL :前后两次探测之间的时间间隔,单位是秒
TCP_KEEPCNT :关闭一个非活跃连接之前的最大重试次数

服务端代码见上

  • ==存在缺陷:==
    • ==2小时时间太长==
    • ==可能 络抖动,导致之前的分节丢失,实际上该连接依旧有效,导致对端误以为终止,进而结束一个有效连接。==
  • ==针对这个问题,目前解决方案两种:==
    • ==第一种:修改内核参数,但是必须要注意大多数内核是基于整个内核维护的这些时间参数的,而不是基于每个套接字,因此如果把无活动周期从2小时修改为自定义的值,将会影响到该主机上所有开启本选项的套接字(默认不开启该选项)。==
    • 第二种:避免使用该选项,应用层维护:
      • 心跳包(hearbeat)
      • 乒乓包(pingpong):和心跳包类似,除了携带标志位外,还可以携带少量数据==
      • 使用TCP的紧急数据位(URG)携带心跳包

FIN_WAIT_2定时器

开始

FIN_WAIT_2定时器发生在TCP四次挥手过程,首先来看一下TCP四次挥手。

  1. 如果对端一直不发送FIN分节,FIN-WAIT-2状态将可能会一直存在。但实际上内核参数tcp_fin_timeout会控制超时时间。本机(cento6.5)默认值为==60s==

结合上图,假设客户端(客户端为主动断开一方)丢失了服务端发来的FIN,服务器必然会重新发送该分节,客户端必须要维护状态信息,以允许他重新发送最终的那个ACK。要是客户端不维护状态信息,他将会响应一个RST,该分节被服务器解释成一个错误。然而,此时可能还有数据流在传输。因此如果TCP打算执行所有必要的工作以彻底终止某个连接上两个方向的数据流。那么他必须正确处理连接终止序列4个分节中任何一个分节丢失情况。

  1. 允许老的重复分节在 络中消失

因为每个数据包在 络上最长生命周期为MSL,2MSL可以确任何一个数据包都将消失。这样可以防止来自某个连接的老的重复分组在该连接已终止后再现。因为端口、IP资源都会回收,下次在复用。想想,如果你结束了一次支付宝访问,紧接着我又用了你刚才的IP和端口 去请求同一个 站,原先来不及发送的消息结果被我接受了,我有可能就得到你的密码。

解决方法

  1. 使用SO_REUSEADDR和SO_REUSRPORT
  • SO_REUSRADDR选项而言:
    • 在所有TCP服务器程序中,调用bind之前设置SO_REUSRADDR套接字选项
    • 当编写一个可同一时刻在同一主机运行多次的多播应用程序时,设置SO_REUSRADDR套接字选项,并将锁参加的多播组的地址作为本地IP地址捆绑。(这个可以参照nginx的设计)
  • SO_REUSRPORT选项而言:
    • 主要是针对SO_REUSRADDR绑定通配地址和端口后,不能再绑定更为详细的IP和端口
  1. 使用SO_LINGER选项
    本选项指定close函数对面向连接的协议如何操作。默认操作是close立即返回,但是如果有数据残留在套接字发送缓冲区,系统将试着把这些数据发送给对端,然后在继续进行正常的FIN序列。
    然而SO_LINGER选项可以改变这个默认设置。其数据结构如下:

710843a947e9d4ed5eda56cbb387cfbb.png

引用

《TCP/IP详解》

《Unix 络编程:卷2》

《计算机 络自顶向下方法》

相关资源:鸿威台球室计费系统说明书_棋牌室管理系统-专业指导文档类资源…

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年10月15日
下一篇 2020年10月15日

相关推荐