【计算机网络】为什么是TCP四次挥手,可以变成三次吗?

news2024/11/25 10:42:01

【计算机网络】为什么是TCP四次挥手,可以变成三次吗?

文章目录

  • 【计算机网络】为什么是TCP四次挥手,可以变成三次吗?
    • 引言
    • TCP 四次挥手
      • 为什么 TCP 挥手需要四次呢?
      • 粗暴关闭 vs 优雅关闭
    • 什么情况会出现三次挥手?
    • 总结

引言

面美团时,被问到:TCP 四次挥手中,能不能把第二次的 ACK 报文, 放到第三次 FIN 报文一起发送?

虽然我们在学习 TCP 挥手时,学到的是需要四次来完成 TCP 挥手,但是在一些情况下, TCP 四次挥手是可以变成 TCP 三次挥手的

52f35dcbe24a4ca7abb23f292837c707

而且在用 wireshark 工具抓包的时候,我们也会常看到 TCP 挥手过程是三次,而不是四次,如下图:

361207c2e5c34bec8708b79990ba7e99

先来回答为什么 RFC 文档里定义 TCP 挥手过程是要四次?

再来回答什么情况下,什么情况会出现三次挥手?

TCP 四次挥手

TCP 四次挥手的过程如下:

18635e15653a4affbdab2c9bf72d599e

具体过程:

  • 客户端主动调用关闭连接的函数,于是就会发送 FIN 报文,这个 FIN 报文代表客户端不会再发送数据了,进入 FIN_WAIT_1 状态;
  • 服务端收到了 FIN 报文,然后马上回复一个 ACK 确认报文,此时服务端进入 CLOSE_WAIT 状态。在收到 FIN 报文的时候,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,服务端应用程序可以通过 read 调用来感知这个 FIN 包,这个 EOF 会被放在已排队等候的其他已接收的数据之后,所以必须要得继续 read 接收缓冲区已接收的数据;
  • 接着,当服务端在 read 数据的时候,最后自然就会读到 EOF,接着 read() 就会返回 0,这时服务端应用程序如果有数据要发送的话,就发完数据后才调用关闭连接的函数,如果服务端应用程序没有数据要发送的话,可以直接调用关闭连接的函数,这时服务端就会发一个 FIN 包,这个 FIN 报文代表服务端不会再发送数据了,之后处于 LAST_ACK 状态;
  • 客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
  • 服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;
  • 客户端经过 2MSL 时间之后,也进入 CLOSE 状态;

你可以看到,每个方向都需要一个 FIN 和一个 ACK,因此通常被称为四次挥手

为什么 TCP 挥手需要四次呢?

服务器收到客户端的 FIN 报文时,内核会马上回一个 ACK 应答报文,但是服务端应用程序可能还有数据要发送,所以并不能马上发送 FIN 报文,而是将发送 FIN 报文的控制权交给服务端应用程序

  • 如果服务端应用程序有数据要发送的话,就发完数据后,才调用关闭连接的函数;
  • 如果服务端应用程序没有数据要发送的话,可以直接调用关闭连接的函数,

从上面过程可知,**是否要发送第三次挥手的控制权不在内核,而是在被动关闭方(上图的服务端)的应用程序,因为应用程序可能还有数据要发送,由应用程序决定什么时候调用关闭连接的函数,当调用了关闭连接的函数,内核就会发送 FIN 报文了,**所以服务端的 ACK 和 FIN 一般都会分开发送。

FIN 报文一定得调用关闭连接的函数,才会发送吗?

不一定。

如果进程退出了,不管是不是正常退出,还是异常退出(如进程崩溃),内核都会发送 FIN 报文,与对方完成四次挥手。

粗暴关闭 vs 优雅关闭

前面介绍 TCP 四次挥手的时候,并没有详细介绍关闭连接的函数,其实关闭的连接的函数有两种函数:

  • close 函数,同时 socket 关闭发送方向和读取方向,也就是 socket 不再有发送和接收数据的能力。如果有多进程/多线程共享同一个 socket,如果有一个进程调用了 close 关闭只是让 socket 引用计数 -1,并不会导致 socket 不可用,同时也不会发出 FIN 报文,其他进程还是可以正常读写该 socket,直到引用计数变为 0,才会发出 FIN 报文。
  • shutdown 函数,可以指定 socket 只关闭发送方向而不关闭读取方向,也就是 socket 不再有发送数据的能力,但是还是具有接收数据的能力。如果有多进程/多线程共享同一个 socket,shutdown 则不管引用计数,直接使得该 socket 不可用,然后发出 FIN 报文,如果有别的进程企图使用该 socket,将会受到影响。

如果客户端是用 close 函数来关闭连接,那么在 TCP 四次挥手过程中,如果收到了服务端发送的数据,由于客户端已经不再具有发送和接收数据的能力,所以客户端的内核会回 RST 报文给服务端,然后内核会释放连接,这时就不会经历完成的 TCP 四次挥手,所以我们常说,调用 close 是粗暴的关闭。

3b5f1897d2d74028aaf4d552fbce1a74

当服务端收到 RST 后,内核就会释放连接,当服务端应用程序再次发起读操作或者写操作时,就能感知到连接已经被释放了:

  • 如果是读操作,则会返回 RST 的报错,也就是我们常见的Connection reset by peer。
  • 如果是写操作,那么程序会产生 SIGPIPE 信号,应用层代码可以捕获并处理信号,如果不处理,则默认情况下进程会终止,异常退出。

相对的,shutdown 函数因为可以指定只关闭发送方向而不关闭读取方向,所以即使在 TCP 四次挥手过程中,如果收到了服务端发送的数据,客户端也是可以正常读取到该数据的,然后就会经历完整的 TCP 四次挥手,所以我们常说,调用 shutdown 是优雅的关闭。

71f5646ec58849e5921adc08bb6789d4

但是注意,shutdown 函数也可以指定「只关闭读取方向,而不关闭发送方向」,但是这时候内核是不会发送 FIN 报文的,因为发送 FIN 报文是意味着我方将不再发送任何数据,而 shutdown 如果指定「不关闭发送方向」,就意味着 socket 还有发送数据的能力,所以内核就不会发送 FIN。

什么情况会出现三次挥手?

当被动关闭方(上图的服务端)在 TCP 挥手过程中,「没有数据要发送」并且「开启了 TCP 延迟确认机制」,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。

d7b349efa4f94453943b433b704a4ca8

然后因为 TCP 延迟确认机制是默认开启的,所以导致我们抓包时,看见三次挥手的次数比四次挥手还多。

什么是 TCP 延迟确认机制?

当发送没有携带数据的 ACK,它的网络效率也是很低的,因为它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报文。 为了解决 ACK 传输效率低问题,所以就衍生出了 TCP 延迟确认。 TCP 延迟确认的策略:

  • 当有响应数据要发送时,ACK 会随着响应数据一起立刻发送给对方
  • 当没有响应数据要发送时,ACK 将会延迟一段时间,以等待是否有响应数据可以一起发送
  • 如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会立刻发送 ACK

33f3d2d54a924b0a80f565038327e0e4

总结

当被动关闭方在 TCP 挥手过程中,如果「没有数据要发送」,同时「没有开启 TCP_QUICKACK(默认情况就是没有开启,没有开启 TCP_QUICKACK,等于就是在使用 TCP 延迟确认机制)」,那么第二和第三次挥手就会合并传输,这样就出现了三次挥手。

所以,出现三次挥手现象,是因为 TCP 延迟确认机制导致的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/651959.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL—SQL优化详解(下)

♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏&#xf…

FFmpeg 内存模型分析

标题 1. 内存模型图2. 分析流程3.追溯本源————源码分析3.1 AVPacket队列 什么时候生成的? 4 .AVPacket和AVFrame相关操作API5. av_read_frame源码分析 1. 内存模型图 2. 分析流程 我们解复用后,媒体流数据就会被分离开来,分别生成对应AVPacketList,然后通过av_…

BART论文解读

1 概述 全称:Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension。BART来源于Bidirectional and Auto-Regressive Transformers发表时间: 2019.10.29团队:Facebook AI Paper地址​arxiv.o…

chatgpt赋能python:Python怎么求解方程

Python怎么求解方程 在数学中,求解方程是一种基本的技能。Python作为一种广泛应用于科学计算和数据分析领域的编程语言,可以帮助我们求解各种类型的方程。Python提供了多个库和函数,使得求解方程在Python中变得非常轻松。 一元方程求解 一…

Android Framework分析SystemServer进程

SystemServer进程是Android系统的核心进程,运行在Android系统启动后,负责管理和加载系统服务。本文将介绍SystemServer进程的详细结构和工作原理,并使用代码注释的方式阐述其关键部分代码。 结构: SystemServer进程的核心是Syste…

SSH基本概念,带你了解SSH

1、SSH基本概念 SSH(Secure Shell)是一种网络协议,用于在不安全的网络中安全地传输数据。它是一种加密协议,可以保护数据在传输过程中不被窃取、篡改或伪造。SSH协议最初是由芬兰的Tatu Ylonen开发的,现在已经成为了一…

Hadoop集群之模板虚拟机的安装

Hadoop集群之模板虚拟机的安装 文章目录 Hadoop集群之模板虚拟机的安装0. 写在前面1. CentOS的安装1.1 配置电脑1.1.1 进入VMware1.1.2 自定义新的虚拟机1.1.3 解决虚拟机的兼容性1.1.4 选择当前虚拟机的操作系统1.1.5 选择虚拟机将来需要安装的系统1.1.6 电脑的具体配置1.1.7 …

KUKA机器人通过示教器进行关机冷启动的具体方法演示

KUKA机器人通过示教器进行关机冷启动的具体方法演示 如下图所示,首先需要登录管理员权限,默认密码:KUKA,然后点击左上角的机器人图标进行菜单选项,找到并点击“关机”选项, 如下图所示,找到并点击“重新启动控制系统PC”, 如下图所示,此时系统提示:确实要重新启动…

chatgpt赋能python:Python生成序列的方法详解

Python生成序列的方法详解 在Python编程中,序列(Sequence)是常用的数据类型之一。序列是有序的,可以通过下标访问其中的元素。Python中有多种方法可以生成序列,下面将对常用的几种方法进行详细介绍。 利用range函数生…

2023-06-16 Android Studio 使用CMakeList编译JNI ,最简单的demo源码

一、代码结构图,代码路径https://download.csdn.net/download/qq_37858386/87913001 二、cmakedemo\app\build.gradle 加下面的代码 externalNativeBuild {cmake {cppFlags "-frtti -fexceptions"}}externalNativeBuild {cmake {path src/main/jni/CMakeL…

国内大模型研究

自从chatgpt发布以来,国内大模型发展非常迅速。我对这项目技术也保持了非常多的持续关注,我一直认识,chatGPT以及其他GPT会给社会带来更大的变革。经过专业训练的大模型可以替代部分客服,部分程序员,部分美工&#xff…

Vue全家桶实战 从零独立开发企业级电商系统(免费升级Vue3.0)

Vue全家桶高仿小米商城–项目简介 文章目录 Vue全家桶高仿小米商城--项目简介电商项目选型--小米商城的页面流程:业务开发流程:项目内容:商城组件部分:课程所包含的知识图谱:章节介绍: 商城的界面展示&…

基于web漏洞扫描及分析系统设计_kaic

基于web漏洞扫描及分析系统设计 摘 要 随着信息技术的发展和网络应用在我国的普及,针对我国境内信息系统的恶意网络攻击也越来越多,并且随着黑客攻击技术的不断地更新,网络犯罪行为变得越来越难以应对,用户日常访问的网站是否安全…

【八大排序(六)】快排终极篇-快速排序非递归版

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:八大排序专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习排序知识   🔝🔝 快排非递归版 1. 前情回顾2. 快排非递归基…

A100 GPU服务器安装CUDNN教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

从Window中先多瞥几眼

JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…

chatgpt赋能python:Python入门:如何添加Seaborn库

Python入门:如何添加Seaborn库 Python是一种易于学习的、功能强大的编程语言,在数据分析和科学计算方面尤其闻名。Seaborn是一个建立在Matplotlib之上的Python可视化库,它提供了一组简单易用的界面,用于绘制优美的统计图形——包…

几个Caller-特性的妙用

System.Runtime.CompilerServices命名空间下有4个以“Caller”为前缀命名的Attribute,我们可以将它标注到方法参数上自动获取当前调用上下文的信息,比如当前的方法名、某个参数的表达式、当前源文件的路径,以及当前代码在源文件中的行号。 一…

RedisSon高并发分布式锁实战RedisSon源码解读

Redis高并发分布式锁实战 1.分布式场景下的synchronized失效的问题–用redis实现分布式锁 synchronized是通过monitor实现的jvm级别的锁,如果是分布式系统,跑在不同的虚拟机上的tomcat上,会导致synchronized无法锁住对象 ----------- 需要分…

读数据压缩入门笔记05_字典转换

1. 瓶颈 1.1. 在网络带宽有限、存储昂贵的时期 1.2. 移动设备正日益成为人们访问互联网的首选的今天 1.3. 数据压缩成了缓解这些瓶颈的关键 2. 字典转换 2.1. dictionary transforms 2.2. 完全改变了人们对数据压缩的认知 2.2.1. 压缩变成了一种对各种类型的数据都有用的…