第二十九篇:图解TCP三次握手,看过不会忘,从底层说清楚,TCP系列四

⼀开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端⼝,处于 LISTEN 状态。

接下来这部分内容的介绍将影响你能不能彻底理解了TCP的三次握手。

一、划重点只有服务端启动了端口监听客户端TCP握手才能建立连接,那么服务端启动的时候都做了哪些工作呢?

1.服务端创建一个套接字(socket)(全局套接字fd)

2.服务端将套接字(socket)绑定在某个端口,然后开始监听

3.启动监听的时候,TCP的软件程序内核会在主机维护一个哈希表存放半连接,该半连接指三次握手客户端发来的SYN报文后服务端生成的初始信息

  4.同时TCP的软件程序内核也会生成一个用链表实现的队列存放全连接全连接指的是三次握手后客户端发来ACK报文后服务端生成的完整连接信息

全连接和半连接都会存放在内存里面,其在内存里的结构如图所示。

随后客户端发起连接握手情况如下

① 第一次握手:客户端发送连接请求

第 1 次握手建立连接时,客户端向服务器发送 SYN 报文(SEQ=X,SYN=1),并进入 SYN_SENT 状态,等待服务器确认,如图所示。

那客户端具体做了哪些事情呢

1)获取文件句柄对应的套接字(socket)对象

2)从用户空间复制要连接的远端IP地址和端口信息

3)设置 socket 状态为 TCP_SYN_SENT

4)动态选择一个端口

5)生成一个连接信息,该信息包含了,报文序列号、最大序列号等;并构造为一个 SYN 包;

客户端会随机初始化一个序号,假设为X,将此序号X置于 TCP ⾸部的「序列号」字段和连接信息的序列号字段中,表示包的序号是X,同时把 SYN 标志位置为 1 ,表示 SYN 报⽂。接着把第⼀个 SYN 报⽂发送给服务端,表示向服务端发起连接,该报⽂不包含应⽤层数据,之后客户端处于 SYN-SENT 状态。

客户端向服务端发送的SYN报文如下图所示。

6)设置TCP头部长度、初始化滑动窗口的大小

7)将第三步生成的连接信息添加到“发送队列”上

8)发送SYN报文

9)启动重传定时器,重传定时器的作用是当报文发送出去了之后,如果特定时间内没有收到确认报文就重发报文。

② 第二次握手:服务器响应 SYN

第 2 次握手实际上是做了两个工作,即 SYN+ACK(请求和确认)报文。

  • 服务器收到了客户端的请求,向客户端回复一个确认信息(ACK=x+1)。
  • 服务器再向客户端发送一个 SYN 包(SEQ=y)建立连接的请求,此时服务器进入 SYN_RECV 状态,如图所示。

此时服务器端做了哪些事情呢

1)服务端查看半连接队列是否满了,如果满了,并且tcp_syncookies 内核参数没有开启,直接丢弃;

2)查看全连接是不是满了,如果满了,且有 young_ack 的话,那么同样也是直接丢弃;

young_ack 是半连接队列里保持着的一个计数器。记录的是刚有SYN到达,没有被SYN_ACK重传定时器重传过SYN_ACK,同时也没有完成过三次握手的sock数量。

3)创建半连接内核对象

4)构造 syn+ack 报文

服务端收到客户端的 SYN 报⽂后,⾸先服务端也随机初始化一个序列号,将此序列号填⼊TCP ⾸部的「序列号」字段中;然后服务端把客户端传来的SYN报文中的X加1(SYN报文数据字段为空,这里默认当作传了一个字节的数据被服务端接收了),表示我收到了序列号为X的一个字节的报文, 然后把X+1 填⼊TCP ⾸部的「确认应答号」字段, 接着把 SYN和 ACK 标志位置为 1 。最后把该报⽂发给客户端,该报⽂也不包含应⽤层数据,之后服务端处于 SYNRCVD 状态。

客户端向服务端发送的ACK+SYN报文如下图所示。

5)发送 syn + ack 响应

6)半连接内核对象添加到半连接队列,并开启计时器

另外第二次握手其实是把两件事合并成了一件事,服务端接收到SYN请求,会给一个ACK应答报文,同时服务端还需要发送一个SYN请求报文,为了不浪费资源,合并在一个报文里面了,称为SYN+ACK报文。

③ 第三次握手:客户端响应 SYNACK

第 3 次握手,是客户端收到服务器的回复(SYN+ACK 报文)。此时,客户端也要向服务器发送确认包(ACK)。此包发送完毕客户端和服务器进入 ESTABLISHED 状态,完成 3 次握手,如图所示。

第三次握手客户端做了哪些事情呢

1)删除发送队列上的连接信息

2)删除SYN报文重发定时器

3)修改 套接字socket 状态为ESTABLISHED状态

4)初始化拥塞控制数据

5)打开连接保活计时器

6)申请和构造 ack 包

客户端收到服务端报⽂后,还要向服务端回应最后⼀个应答报⽂,⾸先设置该应答报⽂ TCP ⾸部 ACK 标志位置为 1 ,其次「确认应答号」字段填⼊ Y + 1 ,最后把报⽂发送给服务端,这次报⽂可以携带客户端到服务器的数据--即可以把请求数据发给服务端了,之后客户端处于 ESTABLISHED 状态。

服务器收到客户端的应答报⽂后,也进⼊ ESTABLISHED 状态。

注:从上⾯的过程可以发现第三次握⼿是可以携带数据的,前两次握⼿是不可以携带数据的

7)将ACK报文发送出去

服务端接收到信息做了什么呢?

  1. 从半连接队列里面获取半连接信息,创建子套接字socket;
  2. 将该半连接从半连接队列删除
  3. 将上面创建的子socket添加入全连接队列
  4. 将子socket的连接状态改成ESTABLISHED

至此,三次握手完成。

不管是全连接队列还是半连接队队列都有最大的长度限制,超过限制,TCP会直接丢弃或者返回RST下面的表格为linux系统的参数介绍

参数名称

说明

tcp_syncookies

当TCP半连接队列SYN队列满之后,开启tcp_syncookies,连接校验通过会直接进入到accept队列

tcp_abort_on_overflow

当TCP全连接队列满之后的策略,0:如果全连接队列满了,服务器端会丢掉客户单发送的ACK,1服务端会发送一个RST给客户端,表示废弃这次连接

TCP全连接队列大小设置

取值是 somaxconn 和backlog之间的最小值,cat /proc/sys/net/core/somaxconn,backlog在TCP程序中指定

tcp_syn_retries

当客户端发送SYN包之后等待服务端返回SYN_ACK,如果客户端很长时间没有收到SYN+ACK报文,会重发SYN包,重发的次数由该参数控制,cat /proc/sys/net/ipv4/tcp_syn_retries

tcp_fastopn

TCP Fastopen,可以减少三次握手的时延,当第一次握手成功后,后续再次握手客户端会携带有第一次握手中服务端返回的cookie,后续不用在进行三次握手,直接连接,0 关闭 1 作为客户端使用 Fast Open 功能 2 作为服务端使用 Fast Open 功能 3 无论作为客户端还是服务器,都可以使用 Fast Open 功能 。 cat /proc/sys/net/ipv4/tcp_fastopen

二、为何不能是两次握手

现在我们假设TCP是两次连接,那会出现以下问题:

① 相同两端可能生成多个连接,导致双方通信困惑,造成混乱

由于网络拥塞,客户端在特定时间内没有收到回复,会通过定时器重新发送一个SYN请求,但是第一个SYN请求并没有丢失,只是后到达,现在客户端和服务端都有两个连接信息,其实就是两个连接,那这会造成什么后果呢?

建立连接后,发送数据,不知道应该交给哪个连接去处理,因为两个以上的连接的信息都是相同的,相同的四元组,数据分片重组发现有分片丢失,这将是灾难的。

② 数据分片重组需要用到序列号,如果采用两次握手,第二次握手可能由于网络原因丢失,客户端没有收到服务端的序列号,此时,如果服务端发送数据给客户端,客户端将无法进行重组,因为它不知道从哪里开始进行重组。

③ 同时,因为可能会建立多个连接,也就是多个“连接信息”,但是其实只需要一个资源就可以了,所以两次连接可能会导致资源浪费。

总结:不能用两次握手的原因包括三点:

1.为了防⽌重复连接初始化,生成多个连接造成混乱

2.同步序列号数据的可靠性需要序列号来保证

3.避免生成多个连接造成资源浪费

三、为何三次握手能解决两次握手带来的问题

客户端连续发送多次 SYN 建立连接的报文,在网络拥堵情况下:

  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。

可以看到,在三次握手的情况下, 可以在服务端建立连接之前,可以阻止掉了历史连接,从而保证建立的连接不是历史连接

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

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

相关文章

ubuntu系统库和Anaconda库冲突问题

之前安装opencv时没出现过这种问题,自从安装Anaconda后就总遇到问题。记录下自己的解决过程。 目录 第一步 第二步 第三步 安装opencv时出现以下问题: /usr/bin/ld: /lib/x86_64-linux-gnu/libwayland-client.so.0: undefined reference to `ffi_prep_cif@LIBFFI_BASE_7.…

若依框架篇-若依集成 X-File-Storage 框架(实现图片上传阿里云 OSS 服务器)、EasyExcel 框架(实现 Excel 数据批量导入功能)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 实现使用 Excel 文件批量导入 1.1 导入功能的前端具体实现 1.2 导入功能的后端具体实现 1.3 使用 EasyExcel 框架实现 Excel 读、写功能 1.4 将 Easy Excel 集成到…

路径跟踪之导航向量场(二)——三维导航向量场

上一期文章介绍了二维平面下的导航向量场计算方法,本期文章将介绍三维空间中,导航向量场及扩展。 本文主要介绍论文[1]中提出的一种基于导航向量场的航迹跟踪算法。此外,虽然本文以三维航迹为例进行介绍,但该方法可非常方便的拓展…

智能优化算法-生物地理学算法(BBO)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 生物地理学优化算法 (Biogeography-Based Optimization, BBO) 是一种基于生物地理学原理的元启发式优化算法,由Dan Simon于2008年提出。BBO通过模拟物种在不同栖息地之间的迁移过程来搜索最优解&…

【JavaEE】——四次挥手,TCP状态转换,滑动窗口,流量控制

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:断开连接的本质 二:四次挥手 1:FIN 2:过程梳理 …

新时代AI桌宠:XGO Rider让你的办公室瞬间高大上

​ XGO Rider Luwu 智能打造了桌面双轮足式机器人 XGO Rider,这款全球首创的轮腿式桌面AI机器人,正在悄然改变我们的办公环境。它不仅是一个高科技玩具,更是一个能大幅提升工作效率和办公室科技感的智能助手。 XGO Rider 新时代“桌宠” micr…

基于java+springboot的宇宙动漫网站

文章目录 前言项目介绍技术介绍功能介绍核心代码数据库参考 系统效果图 前言 文章底部名片,获取项目的完整演示视频,免费解答技术疑问 项目介绍 本系统为用户而设计制作宇宙动漫网站,旨在实现宇宙动漫智能化、现代化管理。本宇宙动漫管理自…

爬虫——scrapy的基本使用

一,scrapy的概念和流程 1. scrapy的概念 Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架。 框架就是把之前简单的操作抽象成一套系统,这样我们在使用框架的时候,它会自动的帮我们完成很…

【数据结构与算法】之有序链表去重(保留重复元素)

目录 1.问题描述 2.思路讲解 3.Java 代码实现 4.代码解释 5.复杂度分析 6.其它方法 6.1 递归实现 6.2 双指针 7.总结 相关教程: 有序链表去重(不保留重复元素) 数据结构之链表详解 递归详解 1.问题描述 给定一个已排序的单链表…

Java可以做人工智能吗-回答是当然可以

Java在人工智能应用开发中的角色与优势 人工智能主要分为两个部分:一个是做底层的大语言模型的训练,另一个是基于大模型进行业务应用。Java最适合做的就是第二个方面,即基于大模型构建业务应用。由于过去大量的企业级应用都是使用Java开发的…

网络服务请求流程简单理解

网络流程: DNS负责将域名解析为IP地址,ALB可以在多个服务实例之间分配流量,APISIX作为API网关处理更细粒度的流量管理,Service在Kubernetes中为Pod提供稳定的访问入口,而Kubernetes则负责整个应用的部署、扩展和运维。…

Java项目-基于springboot框架的逍遥大药房管理系统项目实战(附源码+文档)

作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…

【UML】一个UML学习的还不错的几个帖子

https://segmentfault.com/a/1190000042775634 寂然解读设计模式 - UML类图&类的六大关系-阿里云开发者社区

最佳简历--JAVA程序员的项目经验如何写

小熊学Java全能学习+面试指南:https://www.javaxiaobear.cn 首先你要明确,你能干什么,包括你自己编写的专业技能,到底会不会,怎么运用到技术上的? 1、你能干什么? 你能干什么,其实就展现你的能力,这是简历中最重要的部分,你需要证明前面说的你会的东东; 这就有点…

【前端】如何制作一个自己的网页(14)

当我们还需要对网页中的内容进行局部样式的修改。这时候,就需要用到HTML中的重要元素:span。 span是一个行内元素,可以对HTML文档中的内容进行局部布局。 如图,我们给标题和段落元素的部分内容设置了各种样式。 接下来&#xff0…

rk3588 opencv 的使用

-------------------------------------------------------------------------------------------------------- 目前是 3588 上无法 直接编译出 C程序。 报错如下: -----------------------------------------------------------------------------------------…

LeetCode 精选 75 回顾

目录 一、数组 / 字符串 1.交替合并字符串 (简单) 2.字符串的最大公因子 (简单) 3.拥有最多糖果的孩子(简单) 4.种花问题(简单) 5.反转字符串中的元音字母(简单&a…

[ComfyUI]Flux:爆火禅语小和尚素材!禅意人生,享受自在

在快节奏的现代生活中,人们越来越渴望一种宁静和放松的状态。而禅意小和尚素材正是这样一种能够带给我们内心宁静和智慧的存在。ComfyUI的Flux框架结合了禅意小和尚素材,为我们提供了一个探索禅意人生的独特方式。 禅意小和尚素材源于佛教文化&#xff…

AJAX—— jQuery 发送 AJAX 请求

1、get 请求 $.get(url,[ data ] , [ callback ] , [ type ]) url :请求的 URL 地址 data :请求携带的参数 callback :载入成功时回调函数 type :设置返回内容格式(xml&#xf…