TCP为什么需要四次挥手?

news2025/1/12 18:40:51

tcp为什么需要四次挥手?

答案有两个:

1.将发送fin包的权限交给被动断开发的应用层去处理,也就是让程序员处理

2.接第一个答案,应用层有了发送fin的权限,可以在发送fin前继续向对端发送消息

为了搞清楚这个问题,我们先要了解四次挥手的过程:

在这里插入图片描述

1.注意事项

  • tcp四次挥手过程中没有客户端和服务端的概念,只有主动方和被动方之分
  • 所有的ack包不会自动重传,如果ack包超时或丢失,通过对端重发fin来解决

2.四次挥手的开始条件

  • 主动断开方调用shutdown,关闭读端
  • 主动断开方调用shutdown,关闭写端
  • 主动断开放调用close,关闭读端和写端
  • 主动断开放程序崩溃,关闭双端,协议栈发送RST包

3.第一次挥手详解

  • 主动断开放触发四个条件之一,协议栈会在内核态发送fin包
  • 如果超时时间内未收到ack,协议栈会重发fin
  • 如果由于程序崩溃,协议栈只发送一次RST包,进入快速关闭流程

4.第二次挥手详解

  • 主动关闭方发送fin,向被动方的读缓冲区写入eof结束符,被动方收到可读事件,read返回值为0
  • 被动断开方根据read返回值0判断对方请求关闭连接,但并不知道对方有没有关闭读端
  • 被动断开方可以选择继续发送数据,如果对方关闭读端则数据丢失
  • 直到被动断开放的应用层代码调用close或shutdown或程序崩溃,协议栈会自动发送fin或RST包

5.RST(连接重置)详解

  • 协议栈发送RST是在本端tcp连接非正常断开时进行的
  • 任意一方发送RST或接收到RST都会进入快速关闭流程,释放相应的资源,然后关闭连接

为什么是四次挥手?

  • 如果是三次挥手,那么可能的情况是:
    • 第二次和第三次挥手合并,也就是和tcp连接的三次挥手类似,被动方接收到fin后,协议栈自动发送ack+fin包
    • 三次挥手合并了第二和第三次挥手,最大的不同是:fin由协议栈自动发送,应用层没有权限控制
    • 如果使用三次挥手,那么被动方在发送fin前无法继续发送消息,而且在程序运行过程中进入tcp连接关闭流程,程序员可能并不知道tcp连接关闭的发生,这对代码逻辑有很大的挑战
以上是我个人的理解,下面是gpt-4o的解释:

为什么不能是三次挥手

  1. 可靠性要求
    • TCP协议要求每个FIN和ACK都要独立确认,以确保每一方向另一方清楚地通知了自己的关闭意图。
    • 将ACK和FIN合并在一个包里可能会导致确认过程的不可靠。如果ACK和FIN合并在一个包中,这个包丢失了,将难以确定是否是ACK还是FIN丢失,需要重新发送哪个包。
  2. 流量控制和数据传输的分离
    • 接收FIN包意味着对方已经完成数据发送,但并不意味着接收方也已经完成数据发送。
    • 被动关闭方可能在接收到FIN包后还有数据需要发送,所以它需要有时间处理和发送剩余的数据。
    • 单独的ACK包确保了被动关闭方有时间处理这些数据,而不是立即发送FIN包。
  3. 避免状态混淆
    • 四次挥手的流程清晰地分离了不同的状态:接收FIN、确认FIN、发送FIN、确认关闭。
    • 这种状态分离可以避免在不同阶段的混淆,确保每一步都清楚且明确。

例子解释

如果采用三次挥手,将第二次和第三次挥手合并,情况如下:

  1. 主动关闭方发送FIN。
  2. 被动关闭方接收FIN并发送ACK+FIN。
  3. 主动关闭方接收ACK+FIN,发送ACK,进入TIME_WAIT。

这种情况下:

  • 如果ACK+FIN包丢失,主动关闭方无法区分是ACK还是FIN丢失,需要重新发送哪个包。
  • 被动关闭方在接收到FIN后立即发送ACK+FIN,可能会丢失未发送完的数据。
  • 主动关闭方在接收到ACK+FIN后立即发送ACK并进入TIME_WAIT,可能会导致被动关闭方的数据传输被中断。

结论

四次挥手设计的目的是确保每个关闭步骤都得到确认,保证连接的可靠性和完整性。虽然理论上可以考虑三次挥手,但那样会增加丢包情况下的复杂性和不确定性,违背了TCP协议设计的初衷。四次挥手虽然多了一步,但提供了更高的可靠性和明确的状态分离,有助于实现稳定和可靠的连接关闭过程。
那样会增加丢包情况下的复杂性和不确定性,违背了TCP协议设计的初衷。四次挥手虽然多了一步,但提供了更高的可靠性和明确的状态分离,有助于实现稳定和可靠的连接关闭过程。

推荐学习 https://xxetb.xetslk.com/s/p5Ibb

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

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

相关文章

【java】力扣 反转字符串中的单词

目录 题目描述题目描述思路代码 题目描述 151.反转字符串中的单词 题目描述 思路 主要是利用快慢指针和字符串的截取 还要了解去掉首尾空格的函数是trim 那s"the sky is blue"举例 这个例子是没有首尾空格的,以防万一,我们不管有没有&#…

第06课 Scratch入门篇:侏罗纪公园

侏罗纪公园 入门篇适合新手,如您已经学过,可以忽略本节课! 一、故事背景: 在遥远的过去,有一个充满神秘与惊奇的时代——侏罗纪。那是一个恐龙称霸的时代,各种巨大的生物在这片古老的土地上留下了它们的足…

APT 安装软件详细教程

文章目录 APT 安装软件详细教程APT 概述APT 的基本命令APT 命令详解安装软件包更新和升级软件包删除软件包搜索和查找软件包管理软件包依赖清理软件包缓存APT 配置软件源配置自定义软件源常见问题及解决方案解决软件包依赖问题处理软件源错误其他常见问题使用 APT 的最佳实践总…

【设计模式】工厂模式详解

1.简介 工厂模式是一种创建型设计模式,通过提供一个接口或抽象类来创建对象,而不是直接实例化对象。工厂模式的主要思想是将对象的创建与使用分离,使得创建对象的过程更加灵活和可扩展。 工厂模式主要包括以下角色: 抽象工厂&a…

java 字符串a+b到底生成几个对象?

我们知道,java内存模型是堆栈元空间(也叫方法区,它是在内存中的)。 字符串常量池保存在堆里面。为了节约空间,如果常量池里面有,就不需要创建对象,只需要返回常量池里面的引用;如果…

c#实际开发长到的知识

个人建议先把rotion的库导入进来再操作,具体需要导入的库有,helper库包含了modbus通讯封装好的模块,而mvvm则可以用来做设计mvvm模块,你可以使用里面封装好的实现方法,用起来特别简单更容易实现其中的操作,但是我担心那天被卡脖子了啊啊啊,要是我罗工把库下架了那不是死…

圈子论坛小程序搭建,文章源码链接上传功能社交需求带支付功能

论坛小程序技术栈 前端:uni-app,vue3 后端:PHP,thinkphp8 数据库设计: 设计数据库结构,存储用户数据、帖子数据等。 数据库系统:MySQL5.7 功能开发: 明确小程序的功能需求:浏览、发帖、评…

ChemLLM:化学领域的大模型

人工智能咨询培训老师叶梓 转载标明出处 在化学这一特定学科的应用上,一直缺乏专门的对话模型。化学数据和科学知识通常存储在结构化的数据库中,这给直接使用这些数据训练语言模型带来了挑战。为了解决这一问题,来自上海人工智能实验室的研究…

RabbitMQ高级篇(如何保证消息的可靠性、如何确保业务的幂等性、延迟消息的概念、延迟消息的应用)

文章目录 1. 消息丢失的情况2. 生产者的可靠性2.1 生产者重连2.2 生产者确认2.3 生产者确认机制的代码实现2.4 如何看待和处理生产者的确认信息 3. 消息代理(RabbitMQ)的可靠性3.1 数据持久化3.2 LazyQueue( 3.12 版本后所有队列都是 Lazy Qu…

《七日世界》游玩感想

《七日世界》是一款最近新出的引人入胜的游戏,它以独特的故事情节和精美的画面设计吸引了许多玩家的关注。在这款游戏中,玩家需要在七天的时间里探索一个神秘的幽灵世界,解开其中的谜题,救出被困的灵魂。 首先,让我来聊…

1996-2023年上市公司绿色并购数据(含原始数据+处理代码+计算结果)

1996-2023年上市公司绿色并购数据(含原始数据处理代码计算结果) 1、时间:1996-2023年 2、指标:股票代码、首次公告日期、年份、买方、卖方、标的方、交易概述、标的物名称、标的物说明、买方经营范围、卖方经营范围、标的方经营…

28.jdk源码阅读之CopyOnWriteArraySet

1. 写在前面 CopyOnWriteArraySet 是 Java 中一个线程安全的 Set 实现,它的底层是基于 CopyOnWriteArrayList 实现的。这种数据结构在并发编程中非常有用,因为它在写操作时会创建一个新的数组副本,从而避免了并发修改问题。不知道大家对它的底…

angular入门基础教程(五)父子组件的数据通信

组件之间的通信是我们业务开发中少不了的,先了解下父子组件的通信 父组件传数据给子组件 前面,我们学会会动态属性的绑定,所以在父组件中给子组件绑定属性,在子组件中就可以使用这个属性了。 父组件中声明然后赋值 export class AppCompon…

C语言 | Leetcode C语言题解之第304题二维区域和检索-矩阵不可变

题目: 题解: typedef struct {int** sums;int sumsSize; } NumMatrix;NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {NumMatrix* ret malloc(sizeof(NumMatrix));ret->sums malloc(sizeof(int*) * (matrixSize …

图论:721. 账户合并(并查集扩展)

文章目录 1、题目链接2、题目描述3、并查集思路3.1、按秩合并3.2、常用并查集代码 4、题目解析 1、题目链接 721. 账户合并 2、题目描述 3、并查集思路 并查集可以在很短的时间内合并不同的集合。它的思想为,一开始将不同单元单独作为一个结点,然后按…

【Qt】修改窗口的标题和图标

以下操作仅对顶层 widget(独⽴窗口),有效。 修改窗口的标题 一.windowTitle属性 1.概念 是一种在用户界面中显示窗口的标题的属性。它可以用来设置窗口的标题栏文本。 2.API API说明windowTitle()获取到控件的窗⼝标题.setWindowTitle(const QString& title)设置控件的…

线性回归和逻辑回归揭示数据的隐藏模式:理论与实践全解析

机器学习之线性回归和逻辑回归 1. 简介1.1 机器学习概述1.2 监督学习的定义与重要性1.3 线性回归和逻辑回归在监督学习中的作用1.3.1 线性回归1.3.2 逻辑回归 2. 线性回归(Linear Regression)2.1 定义与目标2.1.1 回归问题的定义2.1.2 预测连续目标变量 …

Redis持久化之RDB和AOF详解

持久化是确保 Redis 数据在服务器重启或崩溃时不丢失的关键功能。由于 Redis 是基于内存的数据库,如果不进行持久化,所有数据都存在于内存中,一旦服务器进程退出,内存中的数据就会丢失。持久化机制可以将 Redis 的数据库状态保存到…

Qt 学习第三天:加一个按钮

本章心得&#xff1a; 这个章节有点像写前端的味道了&#xff0c;设置按钮大小&#xff0c;按钮位置&#xff0c;窗口大小......代码全在widget.cpp上写的 #include "widget.h" #include "ui_widget.h" #include <QPushButton>Widget::Widget(QWid…