计算机网络——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 连接完成中断。

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

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

相关文章

Flink-cdc更好的流式数据集成工具

What’s Flink-cdc? Flink CDC 是基于Apache Flink的一种数据变更捕获技术,用于从数据源(如数据库)中捕获和处理数据的变更事件。CDC技术允许实时地捕获数据库中的增、删、改操作,将这些变更事件转化为流式数据,并能够…

Windows平台C#版RTSP转RTMP直播推送定制版

技术背景 前几年我们发布了C版的多路RTMP/RTSP转RTMP转发官方定制版。在秉承低延迟、灵活稳定、低资源占用的前提下,客户无需关注开发细节,只需图形化配置转发等各类参数,实现产品快速上线目的。 如监控类摄像机、NVR等,通过厂商…

【启程Golang之旅】深入解析函数的奥秘与技巧

欢迎来到Golang的世界!在当今快节奏的软件开发领域,选择一种高效、简洁的编程语言至关重要。而在这方面,Golang(又称Go)无疑是一个备受瞩目的选择。在本文中,带领您探索Golang的世界,一步步地了…

【全开源】海报在线制作系统源码(ThinkPHP+FastAdmin+UniApp)

打造个性化创意海报的利器 引言 在数字化时代,海报作为一种重要的宣传媒介,其设计质量和效率直接影响着宣传效果。为了满足广大用户对于个性化、高效制作海报的需求,海报在线制作系统源码应运而生。本文将详细介绍海报在线制作系统源码的特…

AbMole - 肿瘤发展与免疫器官的“舞蹈”:一场细胞层面的时间赛跑

在生物医学领域,肿瘤与免疫系统之间的相互作用一直是研究的热点话题。肿瘤细胞不是孤立存在的,它们与宿主的免疫系统进行着一场复杂的“舞蹈”。 最近,一项发表在《Molecular & Cellular Proteomics》杂志上的研究,为我们揭开…

【C++】二分查找算法

1.题目 2.算法思路 暴力解法:可以将数组遍历一遍,就可以找到。时间复杂度为O(n)。不算太差,可以接受。 但是有更优秀的解法: 就是二分查找算法。 算法的特点:我们所查找的“数组”具有二段性。这里的二段性不一定有…

Oracle 并行和 session 数量的

这也就是为什么我们指定parallel为4,而实际并行度为8的原因。 insert create index,发现并行数都是加倍的 Indexes seem always created with parallel degree 1 during import as seen from a sqlfile. The sql file shows content like: CREATE INDE…

滑不动窗口的秘密—— “滑动窗口“算法 (Java版)

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接…

《python编程从入门到实践》day39

# 昨日知识点回顾 创建主页、继承模版、显示特定主题页面 # view.py from django.shortcuts import render# 导入所需数据相关联的模型 from .models import Topic# Create your views here. def index(request):"""学习笔记的主页"""#…

Java进阶学习笔记13——抽象类

认识抽象类: 当我们在做子类共性功能抽取的时候,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了。在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类就定义为抽象类…

ISCC2024个人挑战赛WP-迷失之门

&#xff08;非官方解&#xff0c;以下内容均互联网收集的信息和个人思路&#xff0c;仅供学习参考&#xff09; 迷失之门 方法一&#xff1a; IDA看一下 check函数逻辑 进入到check2函数 R键将ascii码转字符&#xff0c;写出逆向脚本 #include <stdio.h> #include &l…

Linux C++ Socket 套接字、select、poll、epoll 实例

文章目录 1. 概述2. TCP 网络编程实例2.1 服务器端2.2 客户端2.3 运行截图 3. I/O 模型3.1 阻塞式I/O模型3.2 非阻塞I/O模型3.3 I/O 复用模型3.4 信号驱动式I/O3.5 异步I/O模型 4. I/O复用之 select4.1 select 函数描述4.2 服务端代码4.3 客户端代码4.4 运行截图 5. I/O复用之 …

RocketMq局部顺序消息

package com.ldj.rocketmq.producer;import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message;import java.nio.charset.StandardCharsets;/*** User: ldj* Date: 2024/5/26* Time: 15:09* Description: 局部顺序消…

css卡片翻转 父元素翻转子元素不翻转效果

css卡片翻转 父元素翻转子元素不翻转效果 vue <div class"moduleBox"><div class"headTitle"><span class"headName">大额案例</span></div><div class"moduleItem"><span class"module…

three.js判断物体在人的前面,还是后面

three.js判断物体在人的前面&#xff0c;还是后面 const player new THREE.Vectors(10, 0, 5); const mesh new THREE.Vectors(15, 0, 6);上面&#xff0c;两个变量分别表示&#xff0c;玩家的位置&#xff0c;物体的位置。 从这发现&#xff0c;当玩家和物体的角度关系 小…

spring boot 整合j2cache 项目启动警告 Redis mode [null] not defined. Using ‘single‘

好 之前的文章 spring boot 整合j2cache 基础操作 在spring boot环境中整合了 j2cache 我们 项目启动时 日志会有一个关键信息 Redis的模式 没有定义 默认使用 single Redis 的这个模式有四种 大家可以自己去网上找一下 做个了解 不用很纠结 我们直接在 j2cache.properties …

一文读懂Apollo客户端配置加载流程

本文基于 apollo-client 2.1.0 版本源码进行分析 Apollo 是携程开源的配置中心&#xff0c;能够集中化管理应用不同环境、不同集群的配置&#xff0c;配置修改后能够实时推送到应用端&#xff0c;并且具备规范的权限、流程治理等特性。 Apollo支持4个维度管理Key-Value格式的配…

比勤奋更重要的是系统思考的能力

不要在接近你问题症状的地方寻找解决办法&#xff0c;要追溯过去&#xff0c;查找问题的根源。通常&#xff0c;最有效的活动是最微妙的。有时最好按兵不动&#xff0c;使系统自我修正&#xff0c;或让系统引导行动。有时会发现&#xff0c;最好的解决办法出现在完全出乎预料的…

HTML蓝色爱心

目录 写在前面 HTML入门 完整代码 代码分析 运行结果 系列推荐 写在后面 写在前面 最近好冷吖&#xff0c;小编给大家准备了一个超级炫酷的爱心&#xff0c;一起来看看吧&#xff01; HTML入门 HTML全称为HyperText Markup Language&#xff0c;是一种标记语言&#…

C++-指针

在C中&#xff0c;指针是至关重要的组成部分。它是C语言最强大的功能之一&#xff0c;也是最棘手的功能之一。 指针具有强大的能力&#xff0c;其本质是协助程序员完成内存的直接操纵。 指针&#xff1a;特定类型数据在内存中的存储地址&#xff0c;即内存地址。 指针变量的定…