TCP-三次握手

TCP-三次握手文章目录三次握手三次握手过程详解三次握手的状态变化面试题:四次挥手三次握手简单示意图:客户端–发送带有SYN标志的数据包–一次握手–服务端服务端–发送带有SYN/ACK标志的数据包–二次握手–客户端客户端–发送带有带有ACK标志的数据包–三次握手–服务端SYN同步序列编号(SynchronizeSequenceNumbers):是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

三次握手

TCP三次握手是浏览器和服务器建立连接的方式,目的是为了使二者能够建立连接,便于后续的数据交互传输。
第一次握手:浏览器向服务器发起建立连接的请求
第二次握手:服务器告诉浏览器,我同意你的连接请求,同时我也向你发起建立连接的请求
第三次握手:浏览器也告诉服务器,我同意建立连接。
至此,双方都知道对方同意建立连接,并准备好了进行数据传输,也知道对方知道自己的情况。接下来就可以传输数据了

简单示意图

一次握手:客户端发送带有 SYN 标志的连接请求数据包给服务端
二次握手:服务端发送带有 SYN+ACK 标志的连接请求和应答数据包给客户端
三次握手:客户端发送带有 ACK 标志的应答数据包给服务端(可以携带数据了)
在这里插入图片描述

详细分析

在这里插入图片描述

0、初始状态:
服务端监听某个端口,处于 LISTEN 状态。

1、客户端发送TCP连接请求
客户端会随机一个初始序列号seq=x(client_isn),
设置SYN=1 ,表示这是SYN握手报文。然后就可以把这个 SYN 报文发送给服务端了,表示向服务端发起连接,之后客户端处于 同步已发送 状态。

2、服务端发送针对TCP连接请求的确认
服务端收到客户端的 SYN 报文后,也随机一个初始序列号(server_isn)(seq=y)
设置ack=x+1, 表示收到了客户端的x之前的数据,希望客户端下次发送的数据从x+1开始。
设置 SYN=1 和 ACK=1。表示这是一个SYN握手和ACK确认应答报文。
最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于 同步已接收 状态。

3、客户端发送确认的确认
客户端收到服务端报文后,还要向服务端回应最后一个应答报文
将ACK置为 1 ,表示这是一个应答报文
ack=y+1 ,表示收到了服务器的y之前的数据,希望服务器下次发送的数据从y+1开始。
最后把报文发送给服务端,这次报文可以携带数据,之后客户端处于 连接已建立 状态。
服务器收到客户端的应答报文后,也进入连接已建立 状态

一些思考

为什么要三次握手,而不是两次?

原因主要有两个:
1、主要原因是为了防止历史连接

三次握手时,在网络拥堵等情况下,第一次握手的SYN包迟迟没能发送到服务端,那么客户端会连续发送多次 SYN 建立连接的报文,那么就可能出现一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;

那么此时服务端就会回一个 SYN + ACK 报文给客户端;

  • 如果是两次握手连接,就不能判断当前连接是否是历史连接,导致错误。

  • 三次握手时,客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,中止这一次连接。

2、三次握手可以避免资源浪费

如果只有「两次握手」,当客户端的 SYN 请求连接在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,

  • 如果是三次握手,第三次握手时服务器可以得到客户端的ack,知道连接已成功建立。
  • 如果没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的 ACK 确认信号,所以每收到一个 SYN 就只能先主动建立一个连接,如果客户端的 SYN 阻塞了,重复发送多次 SYN 报文,那么服务器在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。

SYN 攻击

什么是SYN 攻击?

SYN攻击属于DoS攻击(Denial of Service 拒绝服务)的一种。
SYN攻击大量发送伪造源IP的第一次握手SYN包,服务器每接收到一个SYN包就会为这个连接信息分配核心内存并放入半连接队列,当攻击的SYN包超过半连接队列的最大值时,正常的客户发送SYN数据包请求连接就会被服务器丢弃。导致正常的连接请求无法成功。
严重者引起网络堵塞甚至系统瘫痪。

正常流程:
在这里插入图片描述
当服务端接收到客户端的 SYN 报文时,会将其加入到内核的「 SYN 队列」

接着发送 SYN + ACK 给客户端,等待客户端回应 ACK 报文;

服务端接收到 ACK 报文后,从「 SYN 队列」移入到「 Accept 队列」;

应用从「 Accept 队列」取出连接。

受到 SYN 攻击:
在这里插入图片描述

如何防止SYN 攻击?

1、限制ip连接次数:比如限制同一IP一分钟内新建立的连接数仅为10

2、增大半连接状态的连接数容量
但是增大内存资源占用,不推荐。

3、延迟分配连接资源
当服务器收到第一次握手请求时,不马上分配TCP连接资源。而是计算一个随机值,在第二次握手时传给客户端,当客户端返回第三次握手时,服务器验证随机值的正确性,确认无误才会进入 TCP 的连接状态,才会分配资源。
如果是恶意攻击者发送的大量SYN报文,只要服务器不为其分配资源,也不至于遭到严重破坏了。
在这里插入图片描述

数据包丢失了该怎么办?

1、TCP 第一次握手的 SYN 丢包了,会发生什么?
重传 SYN 数据包,重传次数超过阈值后放弃

2、TCP 第二次握手的 SYN、ACK 丢包了,会发生什么?
客户端 SYN 包没有收到ACK,所以会超时重传
服务端 SYN包也没有收到ACK, 也会超时重传。

3、TCP 第三次握手的 ACK 包丢了,会发生什么?
服务端会一直重传 SYN、ACK 包,重传次数超过阈值后放弃
客户端根据是否开启保活机制分为两种情况:

  • 开启了保活机制的话,会经过 2 小时 11 分 15 秒发现一个「死亡」连接,于是客户端就会断开连接。

  • 没有开启的话,则会一直重传该数据包,直到重传次数超过阈值后就会断开 TCP 连接。

初始序列号为什么随机产生?

为了网络安全
如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间通信的初始化序列号,并且伪造序列号进行攻击,这已经成为一种很常见的网络攻击手段。

为什么 SYN 段不携带数据却要消耗一个序列号呢?

因为SYN 段需要对方的确认,所以需要占用一个序列号确保这个确认不会出现歧义。如果不占序列号的话,怎么知道这个确认是对数据包的确认还是对syn报文的确认呢?

每次握手可以确定哪些东西?

第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常

第二次握手:Client 确认了自己发送、接收正常,对方发送、接收正常;

第三次握手:Server 确认了自己发送正常,对方接收正常

一个已经建立的 TCP 连接中,客户端中途宕机了,客户端恢复后,向服务端发送SYN包重新建立连接,此时服务端会怎么处理?

我们知道TCP 连接是由「四元组」唯一确认的。
然后这个场景中,客户端的IP、服务端IP、目的端口并没有变化
所以这个问题关键在于:本次连接的源端口是否和上一次连接的源端口相同。
所以分两种情况:

1、不相同
此时服务端会认为是新的连接要建立,于是就会通过三次握手来建立新的连接。

那旧连接里的服务端会怎么样呢?
如果服务端发送了数据包给客户端,由于客户端的连接已经被关闭了,此时客户的内核就会回 RST 报文,服务端收到后就会释放连接。
如果服务端一直没有发送数据包给客户端,在超过一段时间后, TCP 保活机制就会启动,检测到客户端没有存活后,接着服务端就会释放掉该连接。

2、相同
在这里插入图片描述
处于 establish 状态的服务端会回复一个携带了对上次报文的确认号和序列号,这个 ACK 被称之为 Challenge ACK。
接着,客户端收到这个 Challenge ACK,发现序列号并不是自己期望收到的,于是就会回 RST 报文,服务端收到后,就会释放掉该连接。

如何手动关闭一个TCP连接

结论:伪造一个能关闭 TCP 连接的 RST 报文
这个合法的 RST 报文必须同时满足「四元组相同」和「序列号正好落在对方的滑动窗口内」这两个条件。
怎么伪造?
直接伪造符合预期的序列号是比较困难,因为如果一个正在传输数据的 TCP 连接,滑动窗口时刻都在变化,因此很难伪造一个刚好落在对方滑动窗口内的序列号的 RST 报文。
办法还是有的,我们可以伪造一个四元组相同的 SYN 报文,来拿到“合法”的序列号!
怎么拿到?
如果处于 establish 状态的服务端,收到四元组相同的 SYN 报文后,会回复一个 Challenge ACK,这个 ACK 报文里的「确认号」,正好是服务端下一次想要接收的序列号,说白了,就是可以通过这一步拿到服务端下一次预期接收的序列号。
然后用这个确认号作为 RST 报文的序列号,发送给服务端,此时服务端会认为这个 RST 报文里的序列号是合法的,于是就会释放连接!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/186298.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Java和C++的区别

    Java和C++的区别Java和C++的区别:1.Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码。对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了。2.C++是编译型语言,所谓编译型语言,就是源码一次编译,直接在编译的过程中链接了,形成了机器码。3.C++比Java执行速度快,但是Java可以利用JVM跨平台。4….

  • VBA编程_常用函数总结1[通俗易懂]

    VBA编程_常用函数总结1[通俗易懂]文章目录IsEmptyReplaceAscMidRoundIsEmpty  用于判断单元格是否为空:SubMain()ActiveSheet.Cells(7,3).Value=1IfIsEmpty(ActiveSheet.Cells(7,3))ThenDebug.Print”IsEmpty”ElseDebug.Print”NotEmpty”EndIfEndSubReplace  函数原型如下

  • linux服务器配置jdk环境变量

    因为Java项目部署需要Java运行环境jdk,要在Linux服务器上部署Java项目,就必须线安装好jdk并配置好环境变量;本篇文章记录了如何安装jdk以及配置环境变量。1.下载jdk2.使用sftp工具将下载的jdk文件上传到Linux服务器上3.将jdk文件移动到/usr/local/java路径下mvjdk-8u171-linux-x64.tar.gz…

  • 查看windows激活状态 命令

    查看windows激活状态 命令1、slmgr.vbs-dlv命令可以查询到Win10的激活信息,包括:激活ID、安装ID、激活截止日期等信息。2、slmgr.vbs-dli命令可以查询到操作系统版本、部分产品密钥、许可证状态等。3、slmgr.vbs-xpr命令可以查询Win10是否永久激活。4、winver命令可以查询系统内核版本,以及注册用户信息…

  • java语言算法描述_六大java语言经典算法[通俗易懂]

    java语言算法描述_六大java语言经典算法[通俗易懂]在程序员们进行编程的时候,对各种数据的处理是少不了的,java语言算法在这个时候就十分重要了。数据算法有很多种,也并不区分哪种计算机语言使用,但是有程序员们常用的java语言经典算法,下面就简单介绍一下六大经典java语言算法。一、冒泡排序(BubbleSort)1、基本思想:两个数比较大小,较大的数下沉,较小的数冒起来。2、算法描述:(1)比较相邻的元素。如果第一个比第二个大,就交换它们两个;…

  • Futex系统调用,Futex机制,及具体案例分析[通俗易懂]

    Futex系统调用,Futex机制,及具体案例分析[通俗易懂]Futex1、背景1.1自己实现锁1.1.1自旋锁1.1.2sleep+自旋1.1.3小结1.2futex1.2.1什么是Futex1.2.2futex诞生之前1.2.3futex诞生之后2、Futex系统调用3、Futex机制4、具体案例分析4.1在Bionic中的实现4.2C语言实现5、参考及扩展阅读首先要区分一下futex系统调用和futex机制。futex系统调用是操作系统提供给上层的系统调用接口。而futex机制是使用futex接口实现的一种锁。1、背景线程同步可以说

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号