• TCP的三次握手四次挥手


    一、三次握手

    1.wireshark 抓包

    2.TCP报文手部

    注意标志位:

    1).同步 SYN = 1 表示这是一个连接请求或连接接受报文。 

    2).只有当 ACK = 1 时确认号字段才有效。当 ACK = 0 时,确认号无效。 

    3).FIN = 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。 

    3.连接示意

    二、四次挥手

    1.知所以然

    为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

    这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)

    放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部

    发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意

    现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

      更明了的回答:由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一

    个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行

    关闭的一方将执行主动关闭,而另一方执行被动关闭。

    2.图示

    第一阶段

    1. 首先client会发送一个FIN包给server(同时还有ack和seq包),这是要告诉server,我已经没有数据要发给你了,此时client处于FIN_WAIT_1状态。接收到FIN包的server处于CLOSE_WAIT的状态。
    2. server发回一个ACK(值为client传过来的seq+1)和seq(值为client传过来的ack的值)给client。client收到server发过来的包后确认关闭连接,此时client处于FIN_WAIT_2。

    第二阶段

    1. server在接收到client的FIN后,得知client要断开tcp连接了,于是在发送完ack和seq给client后,自己发送一个FIN包给client(也带有ack和seq包),告诉client我也要断开连接了,此时server处于LAST_ACK状态。
    2. client接收到server的FIN信息后,会回复server一个ack包,并且会进入TIME_WAIT状态,持续2个MSL(Max Segment Lifetime)。而server接收到client ack后便关闭连接。client在指定时间过后仍然没有接收到server的数据,确认server已经没有数据过来,也关闭了连接。

       (1)、CLOSE_WAIT的解释。
    在以上事例,我们知道server在接收到FIN后,发送ACK之前会进入CLOSE_WAIT,如果长期处于这个状态,或者说服务器出现大量CLOSE_WAIT,说明ACK包一直没有发出,这时候就应该检查代码了。

    (2)、TIME_WAIT注意事项
    从事例我们知道,主动关闭连接的一方会经历TIME_WAIT状态,在该状态下的socket是不会被回收的。而如果是服务器端主动关闭连接,则可能会面临处于大量TIME_WAIT的情况(因为连接很多嘛),会严重影响服务器的处理能力。
    怎么解决呢,那就减少服务器端TIME_WAIT的时间咯。

    (3)2MSL(Maximum Segment Lifetime)存在的理由

    TCP的TIME_WAIT状态也称为2MSL等待状态

    (4)2MSL状态为什么设计在主动关闭这一方

    (1)发最后ack的是主动关闭一方

    (2)只要有一方保持TIME_WAIT状态,就能起到避免incarnation connection在2MSL内的重新建立,不需要两方都有

    三、TCP连接出现大量TIME_WAIT的解决办法

     主动关闭TCP/IP连接,会通过TIME_WAIT的状态保留一段时间,时间过了才会释放这个端口,当端口接受的频繁请求数量过多的时候,

    就会产生大量的TIME_WAIT状态的连接,这些连接占着端口,会消耗大量的资源。

    这个TIME_WAIT的作用是什么?

    原因有二:

    一、保证TCP协议的全双工连接能够可靠关闭

    如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN。 此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。 这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。 所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。 

    二、保证这次连接的重复数据段从网络中消失

    如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。 一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair。 于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。

     

    vi /etc/sysctl.conf
    #当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击 net.ipv4.tcp_syncookies
    = 1

    #允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0 net.ipv4.tcp_tw_reuse = 1

    #开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 net.ipv4.tcp_tw_recycle = 1

    # 默认60 net.ipv4.tcp_fin_timeout = 30

    /sbin/sysctl -p

      

    此外,如果你的连接数本身就很多,我们可以再优化一下TCP/IP的可使用端口范围,进一步提升服务器的并发能力。

    net.ipv4.tcp_keepalive_time = 1200

    表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为20分钟。


    net.ipv4.ip_local_port_range = 10000 65000

    表示用于向外连接的端口范围。缺省情况下很小:32768到61000,改为10000到65000。设的太低,否则可能会占用掉正常的端口


    net.ipv4.tcp_max_syn_backlog = 8192

    表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。


    net.ipv4.tcp_max_tw_buckets = 5000

    表示系统同时保持TIME_WAIT的最大数量,如果超过这个数字,TIME_WAIT将立刻被清除并打印警告信息。默认为180000,改为5000。对于Apache、Nginx等服务器,上几行的参数可以很好地减少TIME_WAIT套接字数量。

    参考:TCP连接的建立和释放

  • 相关阅读:
    MFC创建dc的总结
    mini2440驱动的静态加载
    linux文件IO的操作
    mini2440led驱动分析
    关于layout_gravity和gravity的区别
    UI界面和组件(二)
    UI界面和组件(一)
    关于Android的组件使用中出现的一些问题(一)
    关于Android api文档的一些问题
    梳理7---关于java中static方法一些记录
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/4831755.html
Copyright © 2020-2023  润新知