精华内容
下载资源
问答
  • TCP三次握手和四次挥手不管是在开发还是面试中都是一个非常重要的知识点,它是我们优化web程序性能的基础。欢迎学习,一起进步 文章目录一.TCP简介二.TCP数据报结构三.TCP的三次握手四.TCP四次挥手 一.TCP简介 TCP...
  • TCP 三次握手和四次挥手,面试题详解,图文并茂,欢迎技术交流
  • Wireshark协议分析之TCP的三次握手和四次挥手,内含两个数据包,一个是三次握手,一个是四次挥手
  • 文章目录TCP四次挥手不同情况的研究1.新手加油站1.1 TCP四次握手流程图1.2 TCP头部1.3 四次握手流程详解2.针对挥手不同情况的实验和研究2.1 正常情况2.2 三次挥手情况2.3 CLOSING状态2.4 强制关闭 TCP四次挥手不同...

    TCP四次挥手不同情况的研究

    建议有些网络基础的人查看此文档,当然了新手仔细看也能看懂,大佬直接跳过新手加油站

    1.新手加油站

    1.1 TCP四次握手流程图

    • 首先我们知道传输层TCP协议为了确保可靠连接,会有连接时的三次握手和断开连接时的四次挥手的机制

      我们这里不讨论掉三次握手,来看一下正常四次挥手的流程(如下图所示)

    注意:实际上client和server端都可以先发出断开连接请求,只不过下图演示的是客户端先发起关闭请求

    image-20211018112539626


    1.2 TCP头部

    新手可能看到上面那个图一脸蒙圈,那么我来说明一下,看完说明再理解能更加明了一些(大佬直接跳过)。

    • 首先图的左右两次代表了客户端和服务端,两方都可以先发起请求,不过演示的图片是客户端先发起的。
    • 左边和右边表示各种状态(像终止等待,关闭等待),下边会列举。
    • 中间的FIN,ACK,和seq和ack需要了解TCP的头部和数据部分(详解如下)

    image-20211018113059154

    1. 首先我们发送TCP请求的时候,不光有数据,还有一些TCP协议每次发送都固定必须有的数据,这些数据存在TCP首部中,我们这里不用全知道,只做简单了解。
    2. seq就是头部中的序号------可以简单理解成,假设有1万个数据,太大我们不能一次发送,所以seq可以理解成我这次发送是从这1w个里面的第几个开始的
    3. ack就是对方想要的数据--------假设我们这次发送的是从500开始的,那么seq也就是500,并且假设发送了10个数据,那么对方接收到第509个数据(从500开始,发10个,500也算这次发的,所以最后是509),那么对方现在会告诉你我接到你刚才的数据了,我希望你下次发从第510个数据开始,这时ack为510
    4. 大写的FIN和ACK是上图头部中的6个标志位(上图的那六个字母)中的两个,它们只能为0,1。当FIN为1的时候代表这个包对方是想要跟你断开连接的包,通知你一声。而ACK代表抓个包是对方对你刚才发个它的包的回复。

    1.3 四次握手流程详解

    好了,简单知道了上述内容就可以看我们四次握手的流程了,分为以下四步

    1. 双方都是建立连接状态,客户端想要跟服务器断开连接,于是发了个包,这个包的两个标志为FIN和ACK为1,FIN为1表示想要关闭连接,而ACK为1代表是回复它上个包(因为之前他们肯定进行过数据交互,所以服务器肯定有包发送给客户端,就算没数据包发送,三次握手的时候也是有包的),同样的因为之前有过交互所以这里seq和ack的值不确定,所以用u和v来表示
    2. 服务器告诉对方接收到了。但是此时还没断开连接,双方仍然可以传递数据。
    3. 等到服务器这时候该传的数据传完了,同样的告诉客户端我也可以跟你关闭连接了。
    4. 客户端回复收到了

    状态:

    ​ 上方是流程的一个详解,我们这里主要讨论状态,因为这跟后边四次握手的不同情况有关系。

    • FIN-WAIT-1:表示想主动关闭连接。向对方发送FIN报文后会进入到FIN-WAIT-1状态。

    • CLOSE-WAIT:表示在等待关闭。当对方发送FIN给自己,自己会回应一个ACK报文,此时进入CLOSE——WAIT状态。在此状态下,是需要考虑自己还有没有数据要发给对方,如果没有就发送FIN报文给对方。

    • **FIN-WAIT-2:**接收到了对方的ACK确认后就会进入该状态,并等待对方发送FIN报文。

      ​ 如果接收到了对方同时带FIN,和ACK的报文,就可以直接进入到了TIME-WAIT状态,而无需经过FIN-WAIT-2状态

    • **LAST-ACK:**被动关闭方发送FIN报文后,等待对方的ACK报文,当收到对方的ack报文后进入到close状态。

    • TIME-WAIT:表示主动方收到了对方的FIN报文,并发送了ACK报文,在等待2MSL后即可进入到CLOSED状态了。

      ​ MSL:(Maximum Segment Lifetime,最大分段生存期),是TCP报文在internet上的最长存活时间,每个TCP实现都需要一个具体的MSL,RFC 1122建议是2分钟。所以2MSL就是4分钟。

    • **CLOSED:**关闭状态

    注意:

    ​ 这里解释的状态只是正常的挥手中出现的,还有别的状态下方会讨论到。


    2.针对挥手不同情况的实验和研究

    ​ 以上只是通常情况,四次握手会根据实际的不同,发生不同的变化,下面用Wireshark抓包分析一下。

    2.1 正常情况

    ​ 框起来的是四次挥手,至于上边那三个,有基础的应该知道那是三次握手。可以看到 步骤和我们的之前描述的四次挥手的流程一模一样。

    image-20211018133510082

    1. 客户端想要和服务器断开连接,标志位:FIN,ACK置为1。这里seq是1,ack是1.
    2. 服务器回复客户端接收到了你的请求所以标志位ACK为1。因为上个请求对方ack为1,证明想要我从第一个数据开始发,所以这次我的seq必为1,而对方上次seq是1所以这次我希望它从第2个数据开始发了,所以这次的ack为2.
    3. 服务器感觉事情都忙完了,发给客户端可以断开连接,FIN,ACK置为1。seq和ack都和第二步一样,因为这次他们的值还是根据第一步来的,所以值和第二步是一样一样的。
    4. 客户端回复服务器接收到了。因为上个服务器发来的包ack为2,所以这次我的seq为2,因为上次服务器的seq为1,所以这次我希望它从第2个数据开始发,所以ack为2。

    2.2 三次挥手情况

    注意:

    ​ 这里我写的三次挥手情况,它只是在表面上看来是三次挥手,实际上的步骤没有改变,只不过把第二次和第三次合并了。下方是我用WireShark抓包的截图,其中中间标红的忽略掉只看绿色部分。

    image-20211018120834171

    我们会发现,正常的三次挥手到这里怎么变成了四次了,第二次挥手怎么没了?

    ​ 实际上它还是存在的,就像我上方所说,这种情况是将第二次和第三次合并了,也就是说当客户端发送了关闭连接的请求的时候,服务器因为之前跟你建立连接并且已经把你之前想要的数据传给你了,然后没事了一直等你消息,你一直没动静,早就等的不耐烦了,这时它收到了你的关闭连接请求,好家伙,爷早就不想干了,它快速反应过来我这边数据已经处理完了,于是在回复你消息收到了的同时也告诉你它也想跟你关闭连接。


    2.3 CLOSING状态

    参考:https://blog.csdn.net/dog250/article/details/52070680

    注意:

    ​ 这里重头戏来了,我们之前看了正常TCP断开连接的四次挥手过程。

    ​ 当然还有看上去是经历三次挥手,实际上跟正常的四次挥手过程类似,不过是将第2,3次合并了,具体流程其实还是可以算是一样的。

    特殊情况:

    ​ 那么还有一种情况,就是假如在相同的时间,比如12点整,这个时候客户端和服务器都想和对方断开连接,同时发给对方一个FIN包,那么两边会出现什么情况?

    • 客户端肯定是发了一个FIN包,这时没有接到对面的ACK包,而是接到了对面的FIN包。
    • 服务器端也是一样的,发了一个FIN包,等对面的ACK包,不过ACK包没等到,直接等到了个对方发过来的FIN包。

    这时会出现一个新状态→CLOSING:

    ​ 一种罕见的状态,双方同时都想和对方断开连接,也就是当你发送FIN报文后,没有收到对方的ACK报文反而也收到了对方的FIN报文,那么双方都会进入到CLOSING状态,等待对方的ack报文,如果等待到了对方的ack报文,就直接关闭。

    抓包分析:

    ​ 这里因为要构造TCP连接,所以用了packetdrill,只能在Linux系统中使用,所以人生苦短我用Kali

    注意:

    ​ 脚本不难,但是注意抓包的时候抓的网卡一定要对,我这里抓的是any,我也不知道any是什么,但是看它的线路跟eth0几乎一样,在根据英文,盲猜就是任何网卡的包都抓的意思

    脚本:

    0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
    0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
    0.000 bind(3, ..., ...) = 0
    0.000 listen(3, 1) = 0
    
    0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
    0.100 > S. 0:0(0) ack 1<...>
    0.200 < . 1:1(0) ack 1 win 257
    0.200 accept(3, ..., ...) = 4
    
    // 象征性写入一些数据,装的像一点一个正常的TCP连接:握手-传输-挥手
    0.250 write(4, ..., 3000) = 3000
    
    0.300 < . 1:1(0) ack 3001 win 257
    
    // 主动断开,发送FIN
    0.400 close(4) = 0
    // 在未对上述close的FIN进行ACK前,先FIN
    0.500 < F. 1:1(0) ack 3001 win 260
    // 至此,成功进入同时关闭的CLOSING状态。
    
    
    // 由于packetdrill不能用dup调用,也好用多线程,为了维持进程不退出,只能等待
    10000.000 close(4) = 0
    
    

    结果如图所示:

    ​ kali里面自带wireshark,抓包结果如下,可以看见出现了两个FIN,ACK

    这里详解一下下面几个问题:

    假设43515端口是客户端,8080端口是服务器

    image-20211021102714278

    image-20211021105418170

    • 超时重传问题

    ​ 正常当同时出现FIN的时候,双方等待对方的ack并且如果接收到ACK就进入TIME-WAIT状态,等过了时间就关闭了,如果没接收到对方的ACK,就会重传FIN包。图中明显是一方没接收到ACK包,一直在重传,这个不用深究,看了大佬的文章总结出来应该是操作系统内核的BUG,了解一下就好

    • 三次挥手和CLOSING状态的区分

      ​ 之前我们讲过三次挥手状态是将第二次挥手,和第三次挥手合并了,那么这两种情况好像啊,怎么区分呢?其实很简单,三次挥手虽然简化了但是步骤没省略所有的seq和ack都是正常的。

      ​ 而CLOSING状态,看好两个FIN包,正常第一个FIN包服务器发送seq 1001给客户端,客户端期望的下次数据是什么?是不是应该是1002,而我们图中第二个FIN包是多少,是不是1001很明显它不是接收到服务器的FIN包后才发回来的,而还停留在上个服务器发的包呢。

    • seq和ack对应不上问题

    ​ 看懂了上面区分问题,这个问题就简单了。客户端发的FIN包,ack是1001,但是服务器给的ACK包的seq确实1002这是为什么?,因为双方都知道,奥,我们的FIN包同时发的,那么按照正常挥手情况你的ACK应该是1002啊,不过现在咱俩冲突了,那他很聪明,就直接按照正常情况给你发了seq为1002的包

    2.4 强制关闭

    ​ 这个就没啥好说的了,基本上就是两种情况

    1. 客户端和服务器连接但是客户端直接关了,没有FIN包,这时候我们的java(我的scoket代码用的java写的)还会负责人的给服务器发个RST,强制断开TCP连接

    image-20211021104502921

    1. 客户端发了FIN,服务器也回了,但是服务器那边没写关闭scoket的代码,所以客户端发FIN,服务器ACK,但是服务器发不了FIN,所以服务器那边也是直接来了个RST

    image-20211021104931284

    展开全文
  • TCP四次挥手-wireshark分析

    千次阅读 2018-08-19 22:40:44
    和前面的三次连接一样,这一次我们来看一下TCP四次挥手的过程,当然了,也可能会失望,因为我捕捉到的只有三次挥手,而不是四次挥手。我们这里规定IP地址为219.223.247.181是Client端,而183.232.250.255是Server端...

    和前面的三次连接一样,这一次我们来看一下TCP四次挥手的过程,当然了,也可能会失望,因为我捕捉到的只有三次挥手,而不是四次挥手。我们这里规定IP地址为219.223.247.181是Client端,而183.232.250.255是Server端,下面就用Client端和Server端来解释四次挥手的过程

    一、wireshark分析

    三次挥手
    这里写图片描述
    第一次挥手
    从下面图片我们可以看到,Client首先发起了断开连接请求,从哪里可以看出这是一个断开连接请求呢?从Flags中的Fin=1标志这是Client已经没有数据要发送了,这个时候就会发送一个请求关闭连接的信息给Server端,同样,这里包含Sequence num = 451、Acknowledgement num =48475;Sequence num表示这一次发送数据的起始序号,而Acknowledgement number=48475 表示Client已经收到了Server端发送的48475之前的所有的数据,期待下一次Server发送的Sequence num = 48475;还有一个就是Acknowledgement = 1表示这是一个应答数据,Acknowledgement 和Fin一起发送就是这个数据报是一个确认和请求关闭连接,具有两重功能。
    这里写图片描述
    第二次和第三次挥手
    这是Server端发送的数据,按照常理这一次应该是Server端发送一个确认数据给Client端(也就是Flags中的Fin = 0,而Acknowledgement=1);但是这里不按常理出牌,直接将Fin=1和Acknowledgement=1,一起合并发过来了。可能是因为上面的TCP Keep-Alive功能造成的?那我们先看一下Server端发送的信息都有些啥?Sequence num = 48475和我们第一次握手分析的结果相同,表示这是Client需要Server发送的Sequence num。Acknowledgement num=4052表示Server接受到了Client发送的Sequence num=4051的数据,期待Client下一次发送的Sequence num = 4052。那么到这里客户端就关闭了。而Server端关闭还需要Client进行一次确认。
    这里写图片描述
    第四次挥手
    从这里我们可以看到Fin=0,而Acknowledgement = 1;表示这只是单纯的一个确认数据,表示Client接收到Server关闭连接的请求。我们看一下Sequence num = 4052和上面分析的结论一致。而Acknowledgement num=48476表示Client收到了Server端发送的Sequence num=48476之前的所有的数据。到这里四次挥手就结束了。
    这里写图片描述

    二、四次挥手

    2.1、四次挥手流程
    • 第一次挥手:Client发送Fin + Acknowledgement 给Server端,表示自己要断开连接,这个时候Client端已经没有数据要发送了。
    • 第二次挥手:Server接收到Client发送的断开请求连接,那么这个时候Server需要发送一个Acknowledgement=1用于确定客户请求断开的信息成功接收了;有时候这个过程也会和第三次握手进行合并,就像上面展示的一样。
    • 第三次挥手:Server如果所有的数据已经接收完毕,这个时候就会发送一个Fin=1,而Acknowledgement=0用于表示Server端已经没有数据要发送了,需要关闭连接。
    • 第四次挥手:Client端需要发送一个Acknowledgement = 1表示这个Client接收到了Server的关闭请求信息,这样一来双方的就都关闭了
    2.2、为什么需要四次挥手

    因为TCP的半连接的特性决定的,TCP是一个全双工通信机制的协议,只有双方都关闭的时候才表示这个连接断开了。??

    展开全文
  • TCP三次握手,四次挥手这是一个非常重要的知识点,我也来总结一下。 关于面试最经常问的问题无非就是: 握手为什么是3次? 2次可以吗? 为什么不是4次呢? 你能不能详细的介绍一下TCP三次握手的详细过程? 能不能说...
  • 该文档详细描述了wireshark抓包分析tcp三次握手四次挥手详解及网络命令,亲自整理,适合新手借鉴
  • WireShark抓取TCP四次挥手报文实战

    万次阅读 2020-07-03 10:48:42
    TCP四次挥手 四次挥手的流程 挥手的过程可以由任何一方发起,这里以服务器端发起为例说明: 第一次挥手:服务器端发出FIN,用来断开服务器端到客户端的数据传送,进入FIN-WAIT-1状态 第二次挥手:客户端收到服务器...

    TCP四次挥手

    四次挥手的流程

    挥手的过程可以由任何一方发起,这里以服务器端发起为例说明:

    1. 第一次挥手:服务器端发出FIN,用来断开服务器端到客户端的数据传送,进入FIN-WAIT-1状态
    2. 第二次挥手:客户端收到服务器端的FIN后,发送ACK确认报文,进入CLOSE-WAIT状态
    3. 第三次挥手:客户端发出FIN,用来断开客户端到服务器端的数据传送,进入LAST-ACK状态
    4. 第四次挥手:服务器端收到客户端的FIN后,发送ACK确认报文,进入TIME-WAIT状态,服务器端等待2个最长报文段寿命后进入Close状态;客户端收到确认后,立刻进入Close状态。在这里插入图片描述

    为什么需要四次挥手

    三次握手时,服务器同时把ACK和SYN放在一起发送到了客户端那里,节省了一次报文的传送。

    四次挥手时,当收到对方的FIN报文时,仅仅表示对方不再发送数据但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方ACK和FIN一般都会分开发送。

    为什么客户端最后还要等待2MSL?

    MSL(Maximum Segment Lifetime):报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

    2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。

    WireShark抓取TCP四次挥手报文实战

    可以使用下面的java代码充当服务器端:

    public class SingleThreadServer2 {
    
        public static final int PORT = 8899;
    
        public static void main(String[] args) throws IOException {
    
            ServerSocket serverSocket = new ServerSocket();
    
            serverSocket.bind(new InetSocketAddress(PORT));
    
            System.out.println("server is start at " + PORT);
    
            while (true) {
                try (
                        Socket socket = serverSocket.accept();
                        InputStream inputStream = socket.getInputStream();
                ) {
                    System.out.println("connect success " + socket.getPort());
    
                    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
    
                    System.out.println("receive from client: " + reader.readLine());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    

    客户端直接使用telnet,telnet localhost 8899。

    第一次挥手报文如下:

    在这里插入图片描述

    第二次挥手报文如下:
    在这里插入图片描述

    第三次挥手报文如下:

    在这里插入图片描述
    第四次挥手报文如下:

    在这里插入图片描述
    更多精彩内容关注本人公众号:架构师升级之路
    在这里插入图片描述

    展开全文
  • TCP四次挥手

    2021-01-18 17:44:01
    TCP四次挥手过程和状态变迁 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。 服务端收到该报文后,就向客户端发送 ACK 应答报文,...

    TCP四次挥手过程和状态变迁

    在这里插入图片描述

    • 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。

    • 服务端收到该报文后,就向客户端发送 ACK 应答报文,接着服务端进入 CLOSED_WAIT 状态。

    • 客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。

    • 等待服务端处理完数据后,也向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。

    • 客户端收到服务端的 FIN 报文后,回一个 ACK 应答报文,之后进入 TIME_WAIT 状态

    • 服务器收到了 ACK 应答报文后,就进入了 CLOSE 状态,至此服务端已经完成连接的关闭。

    • 客户端在经过 2MSL 一段时间后,自动进入 CLOSE 状态,至此客户端也完成连接的关闭。

    每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手。这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态。

    为什么需要四次挥手

    再来回顾下四次挥手双方发 FIN 包的过程,就能理解为什么需要四次了。

    • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。

    • 服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。

    从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,从而比三次握手导致多了一次。

    为什么 TIME_WAIT 等待的时间是 2MSL?

    MSL 是 Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。

    MSL 与 TTL 的区别:MSL 的单位是时间,而 TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡。

    TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是:网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间。

    比如,如果被动关闭方没有收到断开连接的最后的 ACK 报文,就会触发超时重发 Fin 报文,另一方接收到 FIN 后,会重发 ACK 给被动关闭方, 一来一去正好 2 个 MSL。

    2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT 时间内,因为客户端的 ACK 没有传输到服务端,客户端又接收到了服务端重发的 FIN 报文,那么 2MSL 时间将重新计时。

    在 Linux 系统里 2MSL 默认是 60 秒,那么一个 MSL 也就是 30 秒。Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。

    其定义在 Linux 内核代码里的名称为 TCP_TIMEWAIT_LEN:

    #define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT 
                                        state, about 60 seconds  */
    

    如果要修改 TIME_WAIT 的时间长度,只能修改 Linux 内核代码里 TCP_TIMEWAIT_LEN 的值,并重新编译 Linux 内核。

    为什么需要 TIME_WAIT 状态

    主动发起关闭连接的一方,才会有 TIME-WAIT 状态。

    需要 TIME-WAIT 状态,主要是两个原因:

    • 防止具有相同「四元组」的「旧」数据包被收到;
    • 保证「被动关闭连接」的一方能被正确的关闭,即保证最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭

    原因一:防止旧连接的数据包

    假设 TIME-WAIT 没有等待时间或时间过短,被延迟的数据包抵达后会发生什么呢?
    在这里插入图片描述

    • 如上图黄色框框服务端在关闭连接之前发送的 SEQ = 301 报文,被网络延迟了。

    • 这时有相同端口的 TCP 连接被复用后,被延迟的 SEQ = 301 抵达了客户端,那么客户端是有可能正常接收这个过期的报文,这就会产生数据错乱等严重的问题。

    所以,TCP 就设计出了这么一个机制,经过 2MSL 这个时间,足以让两个方向上的数据包都被丢弃,使得原来连接的数据包在网络中都自然消失,再出现的数据包一定都是新建立连接所产生的。

    原因二:保证连接正确关闭

    TIME-WAIT 作用是等待足够的时间以确保最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。

    假设 TIME-WAIT 没有等待时间或时间过短,断开连接会造成什么问题呢?

    在这里插入图片描述

    • 如上图红色框框客户端四次挥手的最后一个 ACK 报文如果在网络中被丢失了,此时如果客户端 TIME-WAIT 过短或没有,则就直接进入了 CLOSE 状态了,那么服务端则会一直处在 LASE-ACK 状态。

    • 当客户端发起建立连接的 SYN 请求报文后,服务端会发送 RST 报文给客户端,连接建立的过程就会被终止。

    如果 TIME-WAIT 等待足够长的情况就会遇到两种情况:

    • 服务端正常收到四次挥手的最后一个 ACK 报文,则服务端正常关闭连接。

    服- 务端没有收到四次挥手的最后一个 ACK 报文时,则会重发 FIN 关闭连接报文并等待新的 ACK 报文。

    所以客户端在 TIME-WAIT 状态等待 2MSL 时间后,就可以保证双方的连接都可以正常的关闭。

    TIME_WAIT 过多有什么危害?

    如果服务器有处于 TIME-WAIT 状态的 TCP,则说明是由服务器方主动发起的断开请求。

    过多的 TIME-WAIT 状态主要的危害有两种:

    • 第一是内存资源占用;

    • 是对端口资源的占用,一个 TCP 连接至少消耗一个本地端口;

    第二个危害是会造成严重的后果的,要知道,端口资源也是有限的,一般可以开启的端口为 32768~61000,也可以通过如下参数设置指定

    net.ipv4.ip_local_port_range

    如果服务端 TIME_WAIT 状态过多,占满了所有端口资源,则会导致无法创建新连接。

    如何优化 TIME_WAIT?

    这里给出优化 TIME-WAIT 的几个方式,都是有利有弊:

    • 打开 net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项;

    • net.ipv4.tcp_max_tw_buckets

    • 程序中使用 SO_LINGER ,应用强制使用 RST 关闭。

    方式一:net.ipv4.tcp_tw_reuse 和 tcp_timestamps

    如下的 Linux 内核参数开启后,则可以复用处于 TIME_WAIT 的 socket 为新的连接所用。

    net.ipv4.tcp_tw_reuse = 1
    

    使用这个选项,还有一个前提,需要打开对 TCP 时间戳的支持,即

    net.ipv4.tcp_timestamps=1(默认即为 1)
    

    这个时间戳的字段是在 TCP 头部的「选项」里,用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳。

    由于引入了时间戳,我们在前面提到的 2MSL 问题就不复存在了,因为重复的数据包会因为时间戳过期被自然丢弃。

    温馨提醒:net.ipv4.tcp_tw_reuse要慎用,因为使用了它就必然要打开时间戳的支持 net.ipv4.tcp_timestamps,当客户端与服务端主机时间不同步时,客户端的发送的消息会被直接拒绝掉。

    方式二:net.ipv4.tcp_max_tw_buckets

    这个值默认为 18000,当系统中处于 TIME_WAIT 的连接一旦超过这个值时,系统就会将所有的 TIME_WAIT 连接状态重置。

    这个方法过于暴力,而且治标不治本,带来的问题远比解决的问题多,不推荐使用。

    方式三:程序中使用 SO_LINGER

    我们可以通过设置 socket 选项,来设置调用 close 关闭连接行为。

    struct linger so_linger;
    so_linger.l_onoff = 1;
    so_linger.l_linger = 0;
    setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));
    

    如果l_onoff为非 0, 且l_linger值为 0,那么调用close后,会立该发送一个RST标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了TIME_WAIT状态,直接关闭。

    但这为跨越TIME_WAIT状态提供了一个可能,不过是一个非常危险的行为,不值得提倡。

    如果已经建立了连接,但是客户端突然出现故障了怎么办?

    TCP 有一个机制是保活机制。这个机制的原理是这样的:

    定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

    在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔,以下都为默认值:

    net.ipv4.tcp_keepalive_time=7200
    net.ipv4.tcp_keepalive_intvl=75  
    net.ipv4.tcp_keepalive_probes=9
    
    • tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制

    • tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;

    • tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。

    也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。
    在这里插入图片描述
    这个时间是有点长的,我们也可以根据实际的需求,对以上的保活相关的参数进行设置。

    如果开启了 TCP 保活,需要考虑以下几种情况:

    第一种,对端程序是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。

    第二种,对端程序崩溃并重启。当 TCP 保活的探测报文发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产生一个 RST 报文,这样很快就会发现 TCP 连接已经被重置。

    第三种,是对端程序崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

    展开全文
  • TCP四次挥手原理

    千次阅读 2019-11-02 17:54:11
    TCP协议\TCP四次挥手
  • TCP四次挥手详解

    千次阅读 多人点赞 2021-11-13 17:12:07
    TCP四次挥手过程和状态变迁 在断开连接之前客户端和服务器都处于ESTABLISHED状态,双方都可以主动断开连接,以客户端主动断开连接为优。 第一次挥手:客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置...
  • TCP通过四次挥手来释放连接 四次挥手的过程如下: 第一次挥手: 客户端向服务器发送一个 FIN 数据包(FIN = 1,seq = u)主动断开连接,报文中会指定一个序列号。 告诉服务器:我要跟你断开连接了,不会再你发...
  • 两张动图-彻底明白TCP的三次握手与四次挥手

    万次阅读 多人点赞 2017-06-04 21:53:54
    背景描述 通过上一篇中网络模型中的IP层的介绍,我们知道网络层,可以实现两个主机之间的...IP协议虽然能把数据报文送到目的主机,但是并没有交付主机的具体应用进程。而端到端的通信才应该是应用进程之间的通信。
  • 理论上来说,tcp四次挥手过程是这样的 但是在今天真机抓包的时候发现了实际四次握手的第二次和第三次貌似是合并在一起了,并没有分成两次来发送(seq和ack的值是没问题的) 如图:整个通信过程的最后3个包为四次...
  • tcp四次挥手,为什么是四次?

    万次阅读 多人点赞 2019-07-04 21:29:34
    四次挥手的原因;为什么要有TIME_WAIT状态?2MSL的的意义;四次挥手中如果有一次挥手失败怎么处理?
  • TCP三次握手及四次挥手
  • TCP四次挥手,CLOSE_WAIT和TIME_WAIT

    千次阅读 2020-03-05 09:43:38
    TCP四次挥手 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。假设终止命令由client端发起。 当客户端数据传输完成,准备断开连接时 1、Client端发送一个FIN报文Server端。(序号为M) 1.1. 表示要...
  • TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
  • TCP四次挥手及原因

    千次阅读 2020-05-31 19:06:09
    一、TCP四次挥手 MSL是TCP报文里面最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。 第一次挥手:A->B,A向B发出释放连接请求的报文,其中FIN(终止位) = 1,seq(序列号)=u;在A发送完...
  • TCP四次挥手和TIME_WAIT

    2017-10-06 10:19:38
    同时关闭 为什么需要四次挥手? 那可能有人会有疑问,在tcp连接握手时为何ACK是和SYN一起发送,这里ACK却没有和FIN一起发送呢。原因是因为tcp是全双工模式,接收到FIN时意味将没有数据再发来,但是还是可以继续发送...
  • TCP四次挥手理解

    2020-01-17 18:33:02
    我们来先看一下TCP 四次挥手的过程和状态变迁,如下图所示: **四次挥手的过程:** - 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文,之后客户端进入 FIN_WAIT_1 状态。 -...
  • TCP四次挥手过程

    万次阅读 多人点赞 2019-07-11 11:27:33
    四次挥手 状态转化:A、B连接建立状态ESTABLISHED -> A终止等待1状态FIN-WAIT-1 -> B关闭等待状态2CLOSE-WAIT -> A终止等待2状态FIN-WAIT-2 -> B最后确认状态LAST-ACK -> A时间等待状态TIME-WAIT ...
  • TCP采用四次挥手来释放连接: 第一次挥手:client发送一个FIN,用来关闭client到server的数据传送,client进入FIN_WAIT_1状态。 第二次挥手:server收到FIN后,发送一个ACKclient,确认序号为收到序号+1(与SYN...
  • 案例测试TCP的三次握手和四次挥手过程。包括C语言写的服务器端程序以及c#写的客户端程序,以及使用wirkshark进行的网络抓包分析TCP三次握手四次挥手的过程。
  • Tcp四次挥手.png

    2020-07-19 11:28:19
    1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的... 4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACKServer,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手
  • 一、TCP三次握手、四次挥手 我们先回顾TCP三次握手、四次挥手的过程。 1、三次握手: Client:请求连接; Server:同意并请求连接; Client:同意。 2、四次挥手: Client:请求关闭; Server:同意; 【Server:...
  • 浅谈 TCP 四次挥手

    万次阅读 2018-02-07 14:42:42
    之前自己学习的网络都是浅尝辄止,最近被人反复问起 TCP 相关的挥手问题的相关问题,有必要整理下自身所学,以提供自己和别人查阅。 下图是 TCP 挥手的一个完整流程,这里引用了 tcpipguide 的流程图,更加直观的...
  • 简述TCP三次握手和四次挥手流程

    千次阅读 2018-07-14 15:30:32
    关于TCP的连接过程,很多从事程序开发的小伙伴应该都听过三握手,可这三握手的细节还是有很多人不太清楚的,特别是有些参数记不清楚,我也经常弄错,所以我根据自己的理解画了两张图,将TCP连接和断开的流程简单...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,890
精华内容 23,156
关键字:

给出tcp四次挥手

友情链接: MISEP.rar