自己理解的TCP三次握手

tcp · 浏览次数 : 17

小编点评

以下是关于TCP三次握手过程的详细解释: 1. **第一次握手**:客户端发送一个SYN报文到服务器,询问服务器是否打开并准备好接受数据。在这个阶段,客户端并不关心服务器是否已经准备好了,它只是想尝试建立连接。 2. **第二次握手**:服务器收到SYN报文后,发送一个SYN-ACK报文给客户端,确认收到SYN报文并询问客户端是否准备好发送数据。在这个阶段,服务器已经知道了客户端的序列号,因为它在第一次握手时从客户端那里收到了SYN报文。 3. **第三次握手**:客户端收到SYN-ACK报文后,再发送一个ACK报文给服务器,表示客户端已准备好发送数据。此时,双方都已知道了对方的序列号,可以安全地发送数据。 三次握手的主要目的是确保双方都已准备好建立连接并进行数据传输。通过这个过程,客户端和服务器之间可以避免错误的连接请求,同时也可以防止重复的连接请求占用系统资源。 至于为什么不是两次或四次握手,原因在于: * **两次握手**:如果只进行两次握手,那么服务器无法确认客户端是否收到了它的SYN-ACK报文。因此,服务器在收到一个SYN报文后,可能会建立多个连接,导致资源浪费和连接混乱。 * **四次握手**:虽然四次握手可以确保更安全地建立连接,但它实际上并没有显著提高连接的成功率。因为在某些情况下,如网络延迟或丢包,客户端可能无法收到服务器的SYN-ACK报文,导致连接失败。 因此,TCP协议选择了三次握手作为建立连接的标准方式。

正文

### TCP 三次握手过程是怎样的?

TCP的建立连接是通过三次握手来进行的。三次握手的过程如下图:

image-20240711211752851

说实话这个很好理解,我称之为N字型

首先我们理解到建立连接是一个虚的概念了对吧?那么我们来设计一个可靠的TCP,首先建立连接是必须的吧?相当于我们打电话,总要先说一句喂---wei?(面向连接正是这个意思!)

那么这里顺便谈谈他们很爱问的一个问题

为什么是三次握手?不是两次、四次?

首先你(客户端)要和我(服务端)打电话,我们再要说出内容时,都需要先确定下,网络如何?对方能否听到吧?

而上图中蓝色的SYN相当于就是问候服务器能否听到,然后服务器的ACK对应的就是我能听到,

而这里我们说的"我能听到"在现实中映射到TCP中就代表着ACK而且是SYN,因为接下来对方会回复你说"好"或者说"原本要和你说的内容"也即是绿色的ACK

然后两次的话,是必然不可行的,双方都确认对方能接收信息才能说这个连接建立成功,那么能准确证明两个不行吗?首先要双方都确认必然要2SYN和2ACK,那么很明显两个ACK的分配,要么(1,1),要么(2,0)这里2,0可以顺序相反,(2,0)意味着单方发出两个ACK必然不行!(1,1)意味着双方都发ack,那么必然在时间上有交错,因为同时发的话,这个ack就没用了,ack有用的前提是收到syn后再发,同时时间交错则也只能保障单次ack生效,在前发的ack无效

所以证毕,至少三次握手

那么四次可行吗?肯定可以啊,不谈那些不太荒唐的,你把server的ack和syn拆分后就可以了,只不过比较浪费带宽

到此如果要实现上述功能我们只需要SYN和ACK便够了,那么又为何带上SeqNum呢?以及ACK的时候要对应的+1呢?仅仅是说对暗号的情况吗?因为我们计算机会维持多个tcp连接,通过这个来知道他对应的是哪个连接吗?是的,但是仅此而已吗?

所以更深层上三次握手还能实现其他功能:

  • 三次握手才可以阻止重复历史连接的初始化(主要原因)
  • 三次握手才可以同步双方的初始序列号
  • 三次握手才可以避免资源浪费
阻止历史连接的初始化

下面是小林的解释,我来用我自己的话,来让自己更好地了解,首先情况是服务端seqNum为90的这个报文发送后,重启了那么又重新想向服务端建立连接,所以发了个新的seqNum为100,如果90的报文仍然到达了服务端,那么服务端会再发送90对应的90+1的ACK+SYN,那么这时你客户端不就可以确认了吗?你就会弄一个RST位为1的报文,给服务端,效果类似说"打错了",然后之后100的服务端会再发送100+1,

同理我们这个"N"的下一个折角处也是可以防止服务端重启后,这个SYN+ACK导致的历史链接的问题

三次握手避免历史连接

然后值得注意的一点是,如果服务端收到客户端报文的顺序是:「旧 SYN 报文」->「新 SYN 报文」

那么服务端并不是说同样地给这个返回RST,因为谁是挑战者不好说!对他来讲90可能是新的也可能是旧的,100同样,所以他采用的是认定先来的

所以他返回的是ChangeACK报文给客户端,这个 ack 报文并不是确认收到「新 SYN 报文」的,而是上一次的 ack 确认号,也就是91(90+1)。说白了,解玲还需系铃人,所以这个RST报文只能由他们的原先发送者确认是否结束

同步双方初始序列号
  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);

序列号在 TCP 连接中占据着非常重要的作用,所以当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步。

避免资源浪费

如果只有「两次握手」,当客户端发生的 SYN 报文在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN由于没有第三次握手,服务端不清楚客户端是否收到了自己回复的 ACK 报文,所以服务端每收到一个 SYN 就只能先主动建立一个连接

如果客户端发送的 SYN 报文在网络中阻塞了,重复发送多次 SYN 报文,那么服务端在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。

与自己理解的TCP三次握手相似的内容:

自己理解的TCP三次握手

### TCP 三次握手过程是怎样的? TCP的建立连接是通过三次握手来进行的。三次握手的过程如下图: 说实话这个很好理解,我称之为N字型 首先我们理解到建立连接是一个虚的概念了对吧?那么我们来设计一个可靠的TCP,首先建立连接是必须的吧?相当于我们打电话,总要先说一句喂 wei?(面向连接正是这个

在nodejs中体验http/2

前言 2015年,HTTP/2 发布,直到2021年公司的项目才开始在实践中应用;自己对http2诸多特点的理解只存在于字面上,于是尝试在nodejs中实践一下,加深自己的理解。 多路复用 同域名下所有通信都在单个连接上完成,消除了因多个 TCP 连接而带来的延时和内存消耗,这在大量请求同时发出的情

TCP内核参数的简单验证

前言 春节假期时学习了下内核参数与nginx的调优 最近因为同事遇到问题一直没有解,自己利用晚上时间再次进行验证. 这里将几个参数的理解和验证结果简单总结一下. 希望能够在学习的过程中将问题解决掉. 其实很后悔没有好好学习代码.现在很多问题都已经到了瓶颈期 无法深入的研究下去. 参数一 net.ip

[转帖]RFC1180

[译] RFC 1180:朴素 TCP/IP 教程(1991) 译者序 本文翻译自 1991 年的一份 RFC(1180): A TCP/IP Tutorial。 本文虽距今将近 20 年,但内容并未过时,这不禁让人惊叹于 TCP/IP 协议栈生命力之强大 。要理解 1991 年在技术发展中处于什么

基于OpenJDK部署clickhouse-local镜像的快捷方法

# 基于OpenJDK部署clickhouse-local镜像的快捷方法 ## 摘要 ``` 前期搭建了一套基于OpenJDK的Clickhouse的服务端的镜像 可以简单使用dbeaver进行连接与使用. 后来发现需求与自己理解的不一样. 更加需要的是一套使用clickhouse-local 进行

【面试题】多线程面试题总结

最近在看面试题,所以想用自己的理解总结一下,便于加深印象。 为什么使用多线程 使用多线程可以充分利用CPU,提高CPU的使用率。 提高系统的运行效率,对于一些复杂或者耗时的功能,可以对其进行拆分,比如将某个任务拆分了A、B、C三个子任务,如果子任务之间没有依赖关系,那么就可以使用多线程同时运行A、B

iptables简要介绍及使用iptables实践NAT技术

# 简介 iptables的文章多如牛毛,但是,我读了一些,发现虽然成体系,但是不便理解,今天就结合自己的理解,好好讲解下,另外,我们也会使用iptables来实验一个nat地址转换的demo,nat转换,通俗地讲,一般是为了解决ipv4公网地址不够用的问题,因此在学校、公司等机构的有公网ip的服务

【实践篇】最全的【DDD领域建模】小白学习手册(文末附资料)

DDD领域建模被各个大小厂商提起并应用,而每个人都有自己的理解,本文就是针对小白,系统地讲解DDD到底是什么,解决了什么问题,及一些建议和实践。本文主要是思想的一种碰撞和分享,希望能对朋友们有所启发或帮助。

Linux_aarch64_head.S到main.c的环境建立

PS:要转载请注明出处,本人版权所有。 PS: 这个只是基于《我自己》的理解, 如果和你的原则及想法相冲突,请谅解,勿喷。 环境说明 无 前言 最开始,我仅仅是对linux比较感兴趣,觉得其很神奇的,能够做到很多事情。后面了解到其源码也是开源的,于是抱着学习的态度,简要的看了看相关的代码,在那个时候

操作系统开发:编写开机引导

操作系统是用来管理与协调硬件工作的,开发一款操作系统有利于理解底层的运转逻辑,本篇内容主要用来理解操作系统是如何启动的,又是如何加载磁盘中的内核的,该系列文章参考各类底层书籍,通过自己的理解并加以叙述,让内容变得更加简单,一目了然,即可学到知识又能提高自己的表述能力。 注释: 该系列笔记是在学习《操