zoukankan      html  css  js  c++  java
  • TCP——四次挥手

    TCP四次挥手流程

    用中文来描述下这个过程:

    Client(可以是客户端,也可以是服务器端): 服务端大哥,我事情都干完了,准备撤了,这里对应的就是客户端发了一个FIN,然后进入 FIN-WAIT-1 状态

    Server:知道了,但是你等等我,我还要收收尾,这里对应的就是服务端收到 FIN 后回应的 ACK

    经过上面两步之后,服务端就会处于 CLOSE_WAIT 状态,客户端处于 FIN-WAIT-2 状态。过了一段时间 Server 收尾完了

    Server:小弟,哥哥我做完了,撤吧,服务端发送了FIN,然后进入 LAST-ACK 状态

    Client:大哥,再见啊,这里是客户端对服务端的一个 ACK,然后进入 TIME-WAIT 状态

    Server:再见,我跑路了,服务端收到 ACK ,然后进入 CLOSED 状态

    Client:等待中...,必须等待 2MSL 个时间,然后进入 CLOSED 状态

    为什么要四次挥手

    TCP连接是双向传输的对等的模式(全双工模式),就是说双方都可以同时向对方发送或接收数据。这就意味着:

    当 Client 发出FIN报文段时,只是表示 Client 已经没有数据要发送了,Client 告诉 Server,它的数据已经全部发送完毕了;但是,这个时候 Client 还是可以接受来自 Server 的数据;

    当 Server 返回ACK报文段时,表示它已经知道 Client 没有数据发送了,但是 Server 还是可以发送数据到 Client 的;

    当 Server 也发送了FIN报文段时,这个时候就表示 Server 也没有数据要发送了,就会告诉 Client ,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

    得出的结论:

    当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了,这时对方会回一个ACK,此时一个方向的连接关闭。

    但是另一个方向仍然可以继续传输数据,等到发送完了所有的数据后,会发送一个FIN段来关闭此方向上的连接,接收方发送ACK确认关闭连接。

    注意,接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的,我只是一个“搬运工”,我无法了解上层的意志

    重要状态

    1. CLOSE_WAIT

    • CLOSE_WAIT出现时机与原因
    出现时机:
    TCP 连接断开时需要进行“四次挥手”,TCP 连接的两端都可以发起关闭连接的请求,若其中一端发起了关闭连接,但另外一端没有关闭连接那么该连接就会处于 CLOSE_WAIT 状态
     
    出现原因:
    通常来说,CLOSE_WAIT 在服务器停留的时间很短,且只会发生在被动关闭连接的一端。除非 Kill 掉进程,否则它是不会消失的,意味着一直占用资源。
    如果发现有大量的 CLOSE_WAIT,那就是被动关闭的一方没有及时发送 FIN(根本原因是没有关闭连接),一般来说有以下几种可能:
    1. 代码问题:请求的时候没有显式关闭 Socket 连接,或者死循环导致关闭连接的代码没有执行到,即 FIN 包没有发出,导致 CLOSE_WAIT 不断累积
    2. 响应过慢 / 超时设置过小:双方连接不稳定,一方 Timeout,另外一方还在处理逻辑,导致 Close 被延后
    • CLOSE_WAIT排查方法

    1、查看网络连接

    查看 TCP 连接中各个状态数量可以使用以下命令:
    netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

    查看 TCP 连接中 CLOSE_WAIT 的数量可以使用以下命令:

    netstat -antop | grep CLOSE_WAIT | wc -l

    通过以上命令可以看到服务器上的 CLOSE_WAIT 将近 1w2,这是个不容小觑的潜在问题。

    2、梳理 TCP 连接流向

    接着我们可以从上图梳理出 CLOSE_WAIT 的连接流向,命令返回里中的 Foreign Address(第 5 栏)代表对方的 IP 地址,即和我们连接着但是却主动关闭了连接的机器。

    3、根据项目数据请求流向还原可能场景

    然后我们可以根据项目数据请求流向,还原出可能的场景,在我这里即是 CLOSE_WAIT 都发生在本机爬虫、代理以及目标网站的连接上。

    毕竟 Program name(最后一栏)都写着 Python 了,且这台服务器上只有爬虫用的 Python。

    • CLOSE_WAIT解决思路

     ..................

    2. TIME_WAIT

    • TIME_WAIT出现原因与查看

    出现时机:

    TIME_WAIT永远是出现在主动发送断开连接请求的一方(下文中我们称之为客户端)。

    客户端在收到服务器端发送的FIN(表示"我们也要断开连接了")后发送ACK报文,并且进入TIME_WAIT状态,等待2MSL(MaximumSegmentLifetime 最大报文生存时间)。
    对于Linux,字段为TCP_TIMEWAIT_LEN硬编码为30秒,对于windows为2分钟(可自行调整)。
     

    等待2ML原因:

    为什么客户端不直接进入CLOSED状态,而是要在TIME_WAIT等待那么久呢,基于如下考虑:
     
      1. 确保远程端处于关闭状态。也就是说需要确保客户端发出的最后一个ACK报文能够到达服务器。
          由于网络不可靠,有可能最后一个ACK报文丢失,如果服务器没有收到客户端的ACK,则会重新发送FIN报文,客户端就可以在2MSL时间段内收到这个这个重发的报文,并且重发ACK报文。
               但如果客户端跳过TIME_WAIT阶段进入了CLOSED,服务端始终无法得到响应,就会处于LAST-ACK状态,此时假如客户端发起了一个新连接,则会以失败告终。
     
           2. 防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失),这一点和为啥要执行三次握手而不是两次的原因是一样的。
     

    排查方法:

    1)ss -tan state time-wait|wc -l
    
    (2)netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
    • TIME_WAIT的危害

    1.占用连接资源

    TIME_WAIT占用的1分钟时间内,相同四元组(源地址,源端口,目标地址,目标端口)的连接无法创建,
    通常一个ip可以开启的端口为net.ipv4.ip_local_port_range指定的32768-61000,如果TIME_WAIT状态过多,会导致无法创建新连接。

    2.占用内存资源

    这个占用资源并不是很多,可以不用担心。

    • TIME_WAIT的解决

    可以考虑如下方式:

    1.增加可用端口范围(修改net.ipv4.ip_local_port_range); 增加服务端口,

    比如采用80,81等多个端口提供服务; 增加客户端ip(适用于负载均衡,比如nginx,采用多个ip连接后端服务器); 增加服务端ip; 这些方式治标不治本,只能缓解问题。

    2.将net.ipv4.tcp_max_tw_buckets设置为很小的值(默认是18000). 当TIME_WAIT连接数量达到给定的值时,所有的TIME_WAIT连接会被立刻清除,并打印警告信息。

    但这种粗暴的清理掉所有的连接,意味着有些连接并没有成功等待2MSL,就会造成通讯异常。

    3.修改TCP_TIMEWAIT_LEN值,减少等待时间,但这个需要修改内核并重新编译。

    4.打开tcp_tw_recycle和tcp_timestamps选项。

    5.打开tcp_tw_reuse和tcp_timestamps选项。

     
     
     
    引用:
    • https://juejin.cn/post/6844903734300901390
    • https://juejin.cn/post/6844903730874171405
  • 相关阅读:
    C++中数字与字符串之间的转换
    关于安卓启动eclipse错误:找不到元素‘d:devices'的声明
    linux相关解压命令
    泛型
    CRUD工程师---番外篇---反射
    CRUD工程师---设计模式
    AOP切面日志
    CRUD工程师---InnoDB存储引擎
    CRUD工程师---InnoDB存储引擎2
    CRUD工程师---InnoDB存储引擎4(表)
  • 原文地址:https://www.cnblogs.com/caoweixiong/p/14622525.html
Copyright © 2011-2022 走看看