本文分享自华为云社区《解密TCP连接断开:四次挥手的奥秘和数据传输的安全》,作者: 努力的小雨 。

TCP 连接断开

在当今数字化时代,互联网已经成为了人们生活中不可或缺的一部分。而在互联网的基础之上,TCP协议扮演着关键的角色,它负责着数据在网络中的可靠传输。在TCP连接的建立过程中,我们已经了解了三次握手的过程和原理。然而,连接的建立只是TCP协议的一部分,同样重要的是连接的断开过程。本文将重点探讨TCP连接的断开过程,包括四次挥手的过程和状态变迁,以及为什么挥手需要四次和为什么需要TIME_WAIT状态。通过深入理解TCP连接断开的过程,我们可以更好地理解网络通信的原理

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

TCP断开连接需要通过四次挥手的方式。双方都有能力主动断开连接,一旦断开连接,主机中的各种「资源」将被释放。那么我们将详细讲解下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状态,这样客户端也完成了连接的关闭。

在TCP连接的断开过程中,我们可以观察到每个方向都需要发送一个FIN报文和接收一个ACK报文,因此通常将这个过程称为四次挥手。

需要注意的一点是,只有主动发起关闭连接的一方,才会进入TIME_WAIT状态。这是因为在关闭连接后,客户端需要等待一段时间(通常为两倍的最大报文段生存时间,也即2MSL)来确保服务端收到了自己的ACK应答报文。这样做的目的是为了防止已经关闭的连接上出现延迟的报文段,确保连接的可靠关闭。而服务端则不需要等待这段时间,因此没有TIME_WAIT状态。

为什么挥手需要四次?

为了更好地理解为什么挥手需要四次,让我们再来回顾一下双方发出FIN包的过程。这样我们就能理解为什么需要四次挥手了。

在关闭连接时,当客户端向服务端发送FIN时,这仅仅表示客户端不再发送数据了,但是它仍然可以接收数据。

当服务端收到客户端的FIN报文时,它首先会回复一个ACK应答报文。然而,服务端可能还有数据需要处理和发送,所以它会等待直到它不再发送数据时,才会发送FIN报文给客户端,表示同意现在关闭连接。

通过上述过程,我们可以看出,服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和FIN通常会分开发送,这就导致了比三次握手多了一次挥手的过程。

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

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

MSL和TTL的区别在于单位。MSL的单位是时间,而TTL是经过的路由跳数。因此,为了确保报文已经自然消亡,MSL应该大于或等于TTL消耗为0的时间。

TIME_WAIT等待2倍MSL的合理解释是:网络中可能存在来自发送方的数据包。当这些数据包被接收方处理后,它会向对方发送响应,因此往返需要等待2倍的时间。就是确保最后一个ACK被服务端接收到了,如果没有接收到也要给足时间让服务器端的第三次挥手的FIN重新传过来。

举个例子,如果被动关闭方没有收到断开连接的最后一个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 状态。

TIME_WAIT 状态的需求主要有两个原因:

  • 防止具有相同「四元组」的「旧」数据包被收到:在网络通信中,每个 TCP 连接都由源 IP 地址、源端口号、目标 IP 地址和目标端口号这四个元素唯一标识,称为「四元组」。当一方主动关闭连接后,进入 TIME_WAIT 状态,它仍然可以接收到一段时间内来自对方的延迟数据包。这是因为网络中可能存在被延迟传输的数据包,如果没有 TIME_WAIT 状态的存在,这些延迟数据包可能会被错误地传递给新的连接,导致数据混乱。通过保持 TIME_WAIT 状态,可以防止旧的数据包干扰新的连接。

  • 保证「被动关闭连接」的一方能被正确关闭:当连接的被动关闭方接收到主动关闭方的 FIN 报文(表示关闭连接),它需要发送一个确认 ACK 报文给主动关闭方,以完成连接的关闭。然而,网络是不可靠的,ACK 报文可能会在传输过程中丢失。如果主动关闭方在收到 ACK 报文之前就关闭连接,被动关闭方将无法正常完成连接的关闭。TIME_WAIT 状态的存在确保了被动关闭方能够接收到最后的 ACK 报文,从而帮助其正常关闭连接。

防止旧连接的数据包

假设TIME-WAIT状态没有适当的等待时间或时间过短,延迟的数据包抵达后可能会引发严重的问题。

例如,服务端在关闭连接之前发送的SEQ = 301报文被网络延迟了。然后,同一端口的TCP连接被复用,并且延迟的SEQ = 301到达了客户端。在这种情况下,客户端有可能正常地接收到这个过期的报文,从而导致数据错乱等严重问题的发生。

为了解决这个问题,TCP设计了一个机制,即经过2MSL的时间,足够让连接中的两个方向上的数据包都被丢弃。这样,原来连接的数据包在网络中自然消失,再出现的数据包一定是由新建立的连接产生的,从而避免了数据错乱等问题的发生。

保证连接正确关闭

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

假设TIME-WAIT没有适当的等待时间或时间过短,断开连接可能会导致以下问题:

例如,如果在四次挥手的过程中,客户端发送的最后一个ACK报文在网络中丢失,并且客户端的TIME-WAIT状态过短或没有设置,则客户端会直接进入CLOSE状态,而服务端则会一直处于LAST-ACK状态。这种情况下,连接无法正常关闭。

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

如果TIME-WAIT等待的时间足够长,会发生以下两种情况:

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

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

因此,客户端在TIME-WAIT状态等待2MSL时间后,可以确保双方的连接都能够正常关闭。

这里再科普一下有关知识,大多数三次握手和四次挥手都没有提到。为什么第三次挥手的时候会发送ack呢?不是正常就是发送fin就可以了吗?

在TCP协议中,除了初始连接的第一个SYN包,其中ACK字段被设置为0,而其他所有的TCP包都会将ACK字段设置为1。这个ACK字段的作用是用来确认接收方已经成功接收到数据。如果有数据需要发送,TCP协议会在发送数据的同时附带ACK来确认对方的数据。如果数据在传输过程中丢失,TCP会进行数据重传。ACK字段是TCP头部必备的,这32个位空着也是空着,那么干脆让除了初始报文段之外的所有报文段的ACK字段都有效。

总结

TCP连接的断开需要通过四次挥手的过程来完成。双方都有能力主动断开连接,并且在断开连接后,各种资源将被释放。四次挥手的过程涉及到双方发送FIN和ACK报文的交互,确保数据的可靠传输和连接的正确关闭。其中,主动关闭方会进入TIME_WAIT状态,等待一段时间来确保对方已经接收到最后的ACK报文。TIME_WAIT状态的存在是为了防止旧连接的数据包干扰新连接,并确保被动关闭方能够正常关闭连接。挥手需要四次的原因是为了确保数据的完整传输和连接的可靠关闭。TIME_WAIT状态等待2倍MSL的时间是为了确保网络中的数据包都已经消失。

点击关注,第一时间了解华为云新鲜技术~

TCP连接断开:为什么要挥手四次的更多相关文章

  1. TCP建立连接的三次握手和TCP连接断开的四次挥手

    1. TCP建立连接的3次握手 2. TCP断开连接的四次挥手 [注意]中断连接端可以是Client端,也可以是Server端. 图3—Client端主动发起关闭连接请求 1. 假设Client端主动 ...

  2. TCP连接为什么三次握手四次挥手

    前几天面试某电商被问住了,问的很细,我就说了说连接过程,必然凉凉.在csdn上找了一篇很详细的博客.https://blog.csdn.net/hyg0811/article/details/1023 ...

  3. TCP连接 断开

     参考:http://blog.csdn.net/cyberhero/article/details/5827181 1.建立连接协议 (三次握手)      (1)客户端发送一个带SYN标志的TCP ...

  4. 【转】Linux下tcp连接断开后不释放的解决办法

    问题:在开发测试时发现断开与服务器端口后再次连接时拒绝连接. 分析:服务器上查看端口占用情况,假设端口为8888. netstat -anp |grep 8888 发现端口8888端口显示被占用(ip ...

  5. Linux下TCP连接断开后不释放的解决办法

    问题:在开发测试时发现断开与服务器端口后再次连接时拒绝连接. 分析:服务器上查看端口占用情况,假设端口为8888. netstat -anp |grep 8888 发现端口8888端口显示被占用(ip ...

  6. TCP/IP 三次握手和四次挥手

    TCP 三次握手 作用:建立TCP连接 1.三次握手是客户端先发起请求到服务器,此时服务器处于LISTEN监听状态,A会先发送一个连接请求的报文---SYN=1,ACK=0,seq=x ,这个包也称为 ...

  7. 4个实验,彻底搞懂TCP连接的断开

    前言 看到这个标题你可能会说,TCP 连接的建立与断开,这个我熟,不就是三次握手与四次挥手嘛.且慢,脑海中可以先尝试回答这几个问题: 四次挥手是谁发起的? 如果断电/断网了连接会断开吗? 什么情况下没 ...

  8. tcp连接是基于socket通信的吗

    https://zhidao.baidu.com/question/1305788160020716299.html ------ 网络七层协议 五层模型 TCP连接 HTTP连接 socket套接字 ...

  9. 可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

    本文由原作者松若章原创发布,作者主页:zhihu.com/people/hrsonion/posts,感谢原作者的无私分享. 1.引言 一道经典的面试题是:从 URL 在浏览器被被输入到页面展现的过程 ...

  10. Java网络编程系列之TCP连接状态

    1.TCP连接状态 LISTEN:Server端打开一个socket进行监听,状态置为LISTEN SYN_SENT:Client端发送SYN请求给Server端,状态由CLOSED变为SYN_SEN ...

随机推荐

  1. java实现的类似于sql join操作的工具类,通用递归,最低需要java8

    直接上代码,缺包的自行替换为自己项目中存在的 import java.util.ArrayList; import java.util.Collection; import java.util.Has ...

  2. C++ 学习笔记、01 | 开发简单职工管理系统遇到的一些问题

    记录开发简单职工管理系统遇到的一些问题,黑马教程 https://www.bilibili.com/video/BV1et411b73Z P147 ~ P166 头文件与源文件 头文件只声明,源文件来 ...

  3. mysqlbinlog输出sql

    ./mysqlbinlog -v --base64-output=DECODE-ROWS ~/Downloads/tymysql2|grep -A4 'ALTER' >~/Downloads/a ...

  4. 鞭尸没 jj

      提前退役了.现在我想说一点无关紧要的闲话.   与其说是 OI 回忆录,不如说是对这主线明确的六年做的一个梳理,倒不一定 OI 强相关. 壹.零度下的相遇 视线就这样交叠 与你   最初接触到 O ...

  5. 聊一聊 TLS/SSL

    哈喽大家好,我是咸鱼 当我们在上网冲浪的时候,会在浏览器界面顶部看到一个小锁标志,或者网址以 "https://" 开头 这意味着我们正在使用 TLS/SSL 协议进行安全通信.虽 ...

  6. c语言代码练习11

    //1-100数字中9的数量 #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> int main(){ int x = 0; int ...

  7. Dubbo3应用开发—Dubbo服务管理平台DubboAdmin介绍、安装、测试

    Dubbo服务管理平台 DubboAdmin的介绍 Dubbo Admin是Apache Dubbo服务治理和管理系统的一部分. Dubbo Admin提供了一套用于服务治理的Web界面,让我们可以更 ...

  8. android 尺寸适配相关

    Android上常见度量单位 px(像素):屏幕上的点,绝对长度,与硬件相关. in(英寸):长度单位. mm(毫米):长度单位. pt(磅):1/72英寸,point. dp(与密度无关的像素):一 ...

  9. Opencv系列之一:简介与基本使用

    1 Opencv简介 Opencv是计算机视觉中经典的专用库,其支持多语言,跨平台,功能强大.Opencv-Python为Opencv提供了Python接口,使得使用者在Python中能够调用C/C+ ...

  10. Java面向对象(高级)

    1.类变量 类变量是被类的所有实例共享的. 类变量具体放的位置在哪?在内存中的那个区域,这和jdk的版本是有关的 静态变量在类加载的时候就生成了,即使没有创建类实例也能访问,当然通过实例来实现 类变量 ...