计算机网络——TCP 协议的三次握手 / 四次挥手

简述

TCP / UDP 协议都是传输层的协议。

UDP 是面向无连接的协议,就是说发送端不在乎消息数据是否传输到接收端了,所以会出现数据丢失的情况,所以可靠性也不高。

TCP 是面向连接的、可靠的、基于字节流的传输层协议。所谓面向连接的,就是必须发送端和接收端必须处于连接状态才能发送数据。可靠的就是无论网路链路出现的什么变化,都可以保证一个报文能够到达接收端。

字节流:用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个 TCP 报文,如果接收方的程序如果不知道消息的边界,是无法读出一个有效的用户消息的。

TCP 建立连接

TCP 是面向连接的,所以传输数据前需要和接收端建立连接,通过三次握手来进行。过程如下图:

图片来源: 小林coding

简单描述一下三次握手:

1. 客户端首先初始化自己的序列号,发送带有 SYN 标识的报文给服务端,表示向服务端发起连接。客户端进入 SYN-SEND 状态。

2. 服务端接收到报文之后,同样初始化自己的序列号,同时将确认应答的序列号,也就是收到的客户端的序列号 + 1,返回给客户端发送带有 SYN + ACK 标识的报文,表示我接收到了你的连接请求,并同意连接。服务端进入 SYN-RCVD 状态。

3. 客户端接收到了服务端发来的应答,将收到的客户端的序列号 + 1,再次向服务端发送带有 ACK 表示的报文,表示我接收到你发的应答了,确认进入连接状态。这次握手是可以携带客户端到服务端的数据。客户端进入 ESTABLISHED 状态,在服务端收到客户端的应答之后也进入 ESTABLISHED 状态。

用一个例子来描述三次握手的情况。

为什么是三次握手

主要原因:三次握手是为了阻止重复历史连接的初始化。

设想一个场景,当客户端向服务端发送一个请求连接的报文之后宕机了,报文在到达服务器前被网络阻塞了,此时服务器并没有收到连接请求,状态没有变化。然后客户端重启之后,再次向服务端发送连接的报文。会出现下面的情况。

假设此时旧的请求报文比新的先到达服务端,然后向客户端发送应答报文,都知道,报文里是包含了客户端的序列号的,假设初始序列号是10,而服务端返回的是11(10+1),而客户端在重启之后发送的序列号是20,所以客户端现在期望收到的报文序列号应该是21(20+1),但是此时收到的是11,那么就会向服务端发送 RST 请求报文, 表示出现了历史连接,此次连接中止。(有内鬼,中止交易)。

而后一段时间之后,新发送的连接请求报文到达服务端,之后就会进行正常的 TCP 连接。用一个图来简单描述一下。

那么两次握手能不能解决历史连接的问题呢。

假设两次握手,那么第一次握手服务端收到客户端的SYN 之后,就进入到了 ESTABLISHED 状态,此时服务端是可以向客户端发送数据了,但是这个时候客户端还没有进入到 ESTABLISHED 状态。服务端向客户端发送 SYN+ACK 的报文之后,客户端如果判断此次是历史连接,那么会回复 RST 中断连接。但在这个期间,如果服务端发送了数据,那么发送的数据可能就丢失了,还浪费了资源。

三次握手之所以能解决历史连接的问题,就是因为如果这是历史连接,在第二次握手时服务端并不会进入到 ESTABLISHED 状态,也就不能发送数据给客户端,不会白白浪费资源。而是在客户端确认了不是历史连接的之后转变状态。

其他原因:同步初始序列号,避免浪费资源

1. 第一次握手,客户端向服务端发送报文。

2. 第二次握手,服务端向客户端发送报文,确认了客户端发送正常,服务端接收正常。

3. 第三次握手,客户端最后向服务端应答报文,确认了服务端发送正常,客户端接收正常。

由此确认了客户端和接收端连接正常。因为握手是会交换序列号的,也就是同步序列号,序列号在传输数据时去除重复的数据,可以根据序列号按序接收。

而两次握手不能确保序列号同步,同时不能确认是否连接正常,假如只有两次握手,少了第三次握手,那么服务端不知道客户端的接收是否正常,如果不正常,那么服务端发送的数据就会丢失,浪费了资源。

握手过程中出现了报文丢失怎么办

当第一次握手丢失了,当客户端向服务端第一次握手,然后客户端迟迟收不到服务端的 SYN+ACK 的报文,就会触发超时重传,重传的报文序列号是一样的。

而超时时间和重传次数也有限制,不可能一直让客户端发送连接请求,浪费资源,在Linux 里,重传次数是 5 ,而每次超时时间是上一次的两倍,一般第一次是 1秒,第二次就是2秒,以此类推,5次重传总耗时就是 1+2+4+8+16+31 = 63秒,大约一分钟,如果5次都丢失,那么就不会再进行连接了。

第二次握手丢失。第二次握手包含了给客户端的回应报文 ACK,和服务端发起建立连接的请求报文 SYN ,如果丢失了,客户端会以为第一次握手丢失了,那么会触发超时重传。正常情况下,客户端接收到第二次握手之后会发送 ACK 响应报文给服务端,但是服务端迟迟都收不到,那么服务端也会触发超时重传机制。

第三次握手丢失。第三次握手是客户端发送给服务端的响应报文,如果丢失了,服务端会认为第二次握手丢失了,所以服务端会触发超时重传机制。

TCP 断开连接的四次挥手

TCP 建立连接时需要发送报文,断开连接时同样需要发送报文。

1. 首先客户端想要断开连接,会发送一个带有 FIN 标识的请求报文给服务端。客户端进入 FIN_WAIT_1 状态。

2. 服务端接收到报文之后会回复给客户端一个带有 ACK 标识的应答报文。服务端进入 CLOSE_WAIT 状态。客户端接收到 ACK 报文之后进入 FIN_WAIT_2 状态。

3. 因为想要断开连接时服务端可能还有数据没有处理完,所以需要等待处理完成,处理完成之后会发送带有 FIN 标识的请求报文给客户端。服务端进入 LAST_ACK 状态。

4. 客户端接收到报文之后最后返回带有 ACK 标识的应答报文给服务端,客户端进入 TIME_WAIT  状态。服务端接收到ACK 报文之后进入到 CLOSE 状态。一段时间之后,客户端会进入 CLOSE 状态,双方都关闭连接。

图片来源 小林coding

可以用打电话的方式来打个比方。

为什么要挥手四次

从每次挥手发送带有标识的报文可以看出来,关闭连接时,客户端向服务端发送 FIN 报文,只是代表客户端已经发送数据完毕了,但是还能接收数据,同样的服务端也是这样。

服务端收到 FIN 报文时,回复一个 ACK 应答报文,表示我收到了你的请求,但是你先等等,我还有数据没处理完,等到我数据处理完了,我再发送客户端一个 FIN 报文表示我也没数据需要处理和发送了。

假设少了一次挥手,比如说服务端只发送了 ACK 报文,客户端就关闭连接的话,会导致还未处理和发送的数据出现错误或者丢失。

不过,在特定情况下,可以将四次挥手合并成三次挥手。比如服务端也没有数据处理和发送时,TCP 存在延迟确认机制且是默认开启的,那么第二次和第三次就会合并,变成三次挥手。

挥手丢失的话会发生什么

和握手相同,如果握手丢失了,发送方迟迟收不到回应,就会认为刚刚的报丢失了,就会触发超时重传机制。同样的是 ACK 报文是不会重传的,假如第二次挥手丢失了,那么客户端收不到 ACK 应答报文,那么就会认为FIN 报文丢失了,那么就会重传 FIN 报文。

简单来说,当前最近的 FIN 报文发送方会经常重传 FIN 报文。

为什么第四次挥手客户端需要等待 2*MSL(报文最长寿命)时间后才进入 CLOSE 状态

在第三次挥手时,服务端会发送 FIN 报文给客户端,关闭连接,但是如果出现了第三次或者第四次挥手丢失的情况,服务端都会触发超时重传机制来重新发送 FIN 报文。

MSL 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间,如果这个大于这个时间客户端还没有收到服务端重新发送的 FIN 报文,那么客户端就认为服务端已经接收到了自己发送的 ACK 应答报文,然后进行 CLOSE 状态,代表 TCP 连接完成中断。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探秘死锁:原理、发生条件及解决方案

探秘死锁:原理、发生条件及解决方案 死锁是多线程编程中常见的一个问题,它会导致程序停止响应,进而影响系统的稳定性和性能。理解死锁的原理、发生条件以及如何预防和解决死锁是编写健壮并发程序的关键。 1. 死锁的定义 死锁是指两个或多个…

Linux--软硬链接

目录 0.文件系统 1.软硬链接 1.1见一下软硬链接 1.2软硬链接的特征 1.3软硬链接是什么,有什么作用(场景) 0.文件系统 Linux--文件系统-CSDN博客 1.软硬链接 1.1见一下软硬链接 1.这是软链接 这个命令在Unix和Linux系统中用于创建一个符号…

SQL刷题笔记day3——第二大值

1题目 我的错误代码: select emp_no,salary from salaries where salary (select salary from salaries group by salary order by salary limit 1,1 ) order by emp_no asc 正确代码: select emp_no,salary from salaries where salary (select sal…

jellyfish安装及使用(Bioinformatics工具-020)

01 背景 基因组survey以测序技术为基础,基于小片段文库的低深度测序,通过K-mer分析,快速获得基因组大小、杂合度、重复序列比例等基本信息,为制定该物种的全基因组de novo测序策略提供有效依据。 jellyfish (水母) 是一个用于快…

Cisco Nexus Leaf上线注册到APIC,并配置带外管理IP操作方法

现场2台Nexus93108交换机需要注册到APIC上,成为Leaf交换机。 在ACI的架构中,所有Leaf节点交换机要连接到SPINE交换机上,我们的spine交换机型号为Nexus 9364 Leaf N93108TC-EX长这样, 前面是48个万兆电口,后面6个端口支持40G或100…

maven打包报错:MalformedInputException: Input length = 1

maven 打包时报错: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.3.1:resources (default-resources) on project ec-work-mes: filtering /Users/ecmaster/svn/ecmaster/ynmk/ynmk-mes/ec-work/ec-work-mes/src/main/resou…

Linux配置nginx代理功能

ywtool运维工具下载链接及介绍: 工具下载/介绍/安装页面 目录 一.nginx proxy功能介绍二.配置nginx proxy功能2.1 新增nginx代理配置2.1.1 反向代理(当前只举例https转https)2.1.2 负载均衡(当前只举例https转https) 2.2 修改nginx代理配置2.2.1 手动修改配置文件2.2.2 通过此脚…

利用java8 的 CompletableFuture 优化 Flink 程序,性能提升 50%

你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…

【数据结构】线性表习题 |顺序表 |链表 |栈和队列

📖专栏文章:数据结构学习笔记 🪪作者主页:格乐斯 前言 线性表习题 |顺序表 |链表 |栈和队列 顺序表和链表 1、 选B 1002(5-1)108* 第i个元素地址X,元素长度Len,第j个元素地址Y 公式:YXL…

Docker进入容器查看内容并从容器里拷贝文件到宿主机

工作中需要从docker正在运行的镜像中复制文件到宿主机,于是便将这个过程记录了下来。 (1)查看正在运行的容器 通过以下命令,可以查看正在运行的容器: docker ps (2)进入某个容器执行脚本 我…

备考AMC8和AMC10竞赛,吃透2000-2024年1850道真题和解析(持续)

多做真题,吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一,通过做真题,可以帮助孩子找到真实竞赛的感觉,而且更加贴近比赛的内容,可以通过真题查漏补缺,更有针对性的补齐知识的短板。 今天我们继续…

Android Audio基础——AudioFlinger回放录制线程(七)

AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程 PlaybackThread 及其派生的子类和录制线程 RecordThread 进行的。 一、基础介绍 1、关系图 ThreadBase:PlaybackThread 和 RecordThread 的基类。 Re…

群晖NAS使用Docker部署WPS Office结 合内网穿透实现远程编辑本地文档

文章目录 1. 拉取WPS Office镜像2. 运行WPS Office镜像容器3. 本地访问WPS Office4. 群晖安装Cpolar5. 配置WPS Office远程地址6. 远程访问WPS Office小结 7. 固定公网地址 wps-office是一个在Linux服务器上部署WPS Office的镜像。它基于WPS Office的Linux版本,通过…

redis--redis Cluster

简介 解决了redis单机写入的瓶颈问题,即单机的redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素无中心架构的redis cluster机制,在无中心的redis集群当中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连…

Redis机制-Redis互斥锁、分布式锁

目录 一 互斥锁 二 分布式锁 Redis实现分布式锁 redisson实现分布式锁 可重入性: 主从一致性(性能差): 一 互斥锁 假设我们现在有一个业务要实现秒杀优惠券的功能,如果是一个正常的流程,线程之间应该…

ThreadLocal为什么会导致内存泄漏?

问题引出: ThreadLocal是为了解决什么问题而产生的? ThreadLocal发生内存泄漏的根本原因是什么? 如何避免内存泄漏的发生?定义 为了解决多个线程同时操作程序中的同一个变量而导致的数据不一致性的问题。   假设现在有两个线程A…

【C++题解】1696. 请输出1~n之间所有的整数

问题:1696. 请输出1~n之间所有的整数 类型:循环 题目描述: 从键盘读入一个整数 𝑛n ,请循环输出 1∼n 之间所有的整数,每行输出 1 个。 比如,假设 n5 ,那么输出结果如下: 1 2 3 4 …

微调Llama3实现在线搜索引擎和RAG检索增强生成功能

视频中所出现的代码 Tavily SearchRAG 微调Llama3实现在线搜索引擎和RAG检索增强生成功能!打造自己的perplexity和GPTs!用PDF实现本地知识库_哔哩哔哩_bilibili 一.准备工作 1.安装环境 conda create --name unsloth_env python3.10 conda activate …

我用 Midjourney 的这种风格治愈了强迫症

在 Midjourney 能够实现的各种布局之中,有两种风格因其简洁、有序而独居魅力,它们就是平铺 (Flat Lay) 和 Knolling (Knolling 就是 Knolling, 无法翻译🤣)。要在现实生活中实现这样的美学效果并不容易,你需要精心挑选各种小物件&…

【JAVA WEB实用与优化技巧】如何自己封装一个自定义UI的Swagger组件,包含Swagger如何处理JWT无状态鉴权自动TOKEN获取

目录 一、Swagger 简介1. 什么是 Swagger?2. 如何使用 Swagger3. Springboot 中swagger的使用示例1. maven 引入安装2. java配置 二、Swagger UI存在的缺点1.不够方便直观2.请求的参数没有缓存3.不够美观4.如果是JWT 无状态登录,Swagger使用起来就没有那…