TCP-三次握手

2023-10-30

三次握手

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 报文里的序列号是合法的,于是就会释放连接!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TCP-三次握手 的相关文章

  • 在 Android 上显示实时 UDP 或 RTP 流(组播)

    我刚接触 Android 开发几周 我需要编写一个应用程序 可以向用户显示以 UDP 或 RDP 多播的实时流 该流位于诸如 rtp 230 0 0 11 1234 之类的地址 并通过该模块通过 WIFI 发出 我已经尝试从播放器 Daro
  • 为什么服务器不使用 C# 中的套接字接收本地传输中的所有 UDP 数据包?

    我有一个服务器和一个客户端应用程序 客户端将一堆数据包发送到服务器 使用的协议是UDP 客户端应用程序生成一个新线程来循环发送数据包 服务器应用程序还生成一个新线程来循环等待数据包 这两个应用程序都需要根据传输进度保持 UI 更新 如何正确
  • 播放 UDP 数据包中收到的原始 PCM 音频

    远程设备正在 UDP 数据包中发送实时原始 PCM 音频 不包含标头 我需要在 java 中实现一个程序来接收这些数据包并在 PC 上实时播放它们 据我所知 原始 PCM 的属性是 16 位 单声道 采样率 24KHz 因此我尝试向该原始
  • UdpClient 在广播地址上接收

    在 c 中 我使用 UdpClient Receive 函数 public void StartUdpListener Object state try udpServer new UdpClient new IPEndPoint IPAd
  • Java UDP中如何获取实际数据包大小`byte[]`数组

    这是我上一个问题的后续问题 Java UDP发送 接收数据包一一接收 https stackoverflow com questions 21866382 java udp send receive packet one by one 正如
  • Android 上的 UDP 视频流

    我有一个 Android 项目 需要构建一个客户端应用程序来接收 UDP 或 RTP 单播视频流并播放它们 不幸的是 我似乎无法使其正常工作 并且已经广泛搜索了解决方案 我已经在 Xoom Android 3 2 和 Nexus S And
  • 如何在多个程序中接收相同的udp流?

    我有一个封闭的第三方系统 它发送单播 UDP 流 MPEG TS 我想在同一台计算机上的两个不同程序中访问该流 我无法更改源上的任何内容 甚至无法更改 IP 或端口 除了编写自己的小程序来捕获流然后创建新流并重新发送这两个流之外 还有其他选
  • udp数据包被tcpdump捕获,但没有被套接字接收[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我编写了一个 rawudp 程序 通过原始套接字发送 udp 数据包 按照网页http www tenouk com Module43a html h
  • 如果客户端在服务器之后启动,则 GStreamer v1.0 UDP 多播流无法正确解码

    我正在尝试使用 GStreamer 进行 UDP 多播屏幕流传输 我的投屏服务器应该在 Windows 上运行 and my 客户端应在 Linux 上运行 如果我在服务器之前启动客户端 一切都很好 问题是当我启动客户端并且服务器已经启动时
  • 更改Windows下的默认套接字缓冲区大小[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我无法更改的应用程序正在丢弃一些传入的 UDP 数据包 我怀疑接收缓冲区溢出 是否有注册表设置可以使默认缓冲区大于 8KB From th
  • HTTP 是否使用 UDP?

    这可能是一个愚蠢的问题 HTTP 是否使用过用户数据报协议 例如 如果使用 HTTP 传输 MP3 或视频 它内部是否使用 UDP 进行传输 From RFC 2616 http www ietf org rfc rfc2616 txt 通
  • 当网络上的所有计算机都具有相同的公共IP地址时,如何向特定计算机发送UDP数据包? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 这就是问题 它非常简单 理解 我家里有 2 台电脑 它们都有相同的公共 IP 地址 例如 1 2 3 4 我在咖啡馆有一台计算机 不同的网络 因此它具
  • 如何监听任意端口的广播包?

    使用 NET 如何在任何端口上侦听发送到 255的udp广播数据包 而不需要绑定到特定端口 我自己找到了办法 它是这样工作的 mainSocket new Socket AddressFamily InterNetwork SocketTy
  • Java UDP 服务器,并发客户端

    下面的代码足以接受并发 UDP 传输吗 更具体地说 如果 2 个客户端同时传输 当我调用 receive 时 DatagramSocket 会将传输排队并一一传送它们 还是只有一个能够通过 DatagramSocket socket new
  • 对等网络应用程序的网络发现

    我希望有两个类 一个服务器类和一个客户端类 服务器类应该接收每个新客户端的 IP 地址和端口号并将它们存储在列表中 它应该为每个客户端提供已连接客户端及其 IP 地址的列表 然后 客户端可以使用 TCP 连接相互通信 问题是客户端不知道服务
  • 为什么通过UdpClient发送会导致后续接收失败?

    我正在尝试创建一个 UDP 服务器 它可以向所有向其发送消息的客户端发送消息 真实情况要复杂一些 但最简单的方法是将其想象为一个聊天服务器 之前发送过消息的每个人都会收到其他客户端发送的所有消息 所有这一切都是通过UdpClient 在单独
  • 提高UDP可靠性

    我正在构建一个基于 UDP 的小型服务器 服务器基于 Net并使用它自己的Socket类 我通过 ReceiveMessageFromAsync 和异步发送使用完成端口 我的问题是我失去了大约 5 10 的流量 现在我明白这是正常的 但是有
  • F1 2019 UDP解码

    我目前正在为 F1 方向盘开发自己的显示器 F1 2019 由codemasters提供 通过UDP发送数据 该数据存储在字节数组中 我在解码返回的数组时遇到一些问题 问题是我得到了很多信息 但我不知道如何处理它们 我将向您介绍我所尝试过的
  • 使用 Boost.Asio 进行广播的问题

    如果问题之前已得到解答 我提前表示歉意 但我已经搜索并没有找到任何对我有帮助的东西 正如问题标题所示 我正在尝试将包从服务器广播到一组侦听任何消息的客户端 客户端将计算一秒钟内收到的消息数 服务器端的事情是这样的 class Server
  • 如何将udp发送到udp node.js服务器?

    我对此很陌生 所以我真的不知道我在做什么 但我已经设置了一个 node js udp 服务器 我想从客户端 来自网站 向它发送一个数据包 但我不知道如何在 javascript 中做到这一点 或者是否可能 我不是在研究如何从 Node js

随机推荐

  • 【数据结构】邻接矩阵法

    邻接矩阵 不带权 define MaxVertexNum 100 顶点的最大数目 typedef struct char Vex MaxVertexNum 顶点表 存放下标 复杂信息 int Edge MaxVertexNum MaxVer
  • 云计算虚拟化技术未来发展的趋势及应用(来源: 比特网)

    近两年 随着一些国际知名的虚拟化软件厂商在中国市场的大力开拓 虚拟化及云计算的概念越来越热 虚拟化软件市场大幅升温 同时也带动了一批国内的虚拟化软件企业迅速的发展起来 虚拟化技术从早期的企业应用 逐步过渡到公有云应用 应用范围越来越广泛 那
  • 刷题day22:逆波兰表达式求值

    题意描述 给你一个字符串数组 tokens 表示一个根据 逆波兰表示法 表示的算术表达式 请你计算该表达式 返回一个表示表达式值的整数 类似于二叉树 可以将运算符号看做二叉树的中间节点 遇到运算符之后计算前两个数字与该运算符的运算结果 C
  • 电阻的精度和温漂

    转载自 http blog sina com cn s blog 68b345970100jc2h html 电阻的精度和温漂 1 电阻温度系数 TCR 表示电阻当温度改变1度时 电阻值的相对变化 当温度每升高1 时 导体电阻的增加值与原来
  • python 字符串去除 等等转义空格换行字符

    python去除html特殊转义字符 下面这些是一些我在网上找的一些 好像都不管用 网络上面的一些方法好像都不管用 比如 str text replace str text replace u xa0 等等一些 我使用的时候好像都不管用 下
  • 匿名内部类方式实现线程创建的三种方式

    小demo package demo04 author wh date 2021年08月30日15 57 匿名内部类方式实现线程创建的三种方式 public class demo02 public static void main Stri
  • 企业级springboot项目架构模板V4.0,开箱即用

    此次 4 0 更新点 1 添加线程池的使用 2 Springboot版本更新2 7 0 解决部分冲突的依赖 3 所有表结构去除 ID 字段 不在使用ID作为主键 主键直接使用算法生成 4 解决过滤器 引起Druid监控无法访问的问题 5 F
  • 3.4 流式操作

    1 简介 1 概念 Stream是数据渠道 用于操作数据源所生成的元素序列 它可以实现对集合的复杂操作 例如过滤 排序和映射等 集合是一种静态的数据结构 存储在内存中 而Stream是通过CPU来实现计算的 并不会存储数据 Stream不会
  • linux 出错 “INFO: task xxxxxx: 634 blocked for more than 120 seconds.”的3种解决方案

    1 问题描述 最近搭建的一个linux最小系统在运行到241秒时在控制台自动打印如下图信息 并且以后每隔120秒打印一次 仔细阅读打印信息发现关键信息是 hung task timeout secs 第一次遇到这样的问题 首先百度 通过翻看
  • 在 Java 中,读取 resources 下的文件方式(四种)

    1 测试文件具体位置 2 方式一 项目内路径 使用项目内路径读取 该路径只在开发工具中显示 所以只能在开发工具中使用 项目部署之后无法读取 不通用 SpringBootTest public class ResourcesFIleTest
  • 爱快路由器设置上网

    进入以太网络设置里面查看详细信息 也可cmdipconfig 找出网管 打开电脑的浏览器 地址栏输入 10 100 10 1 在登录界面爱快路由器帐号和密码 默认帐号 admin 默认密码 admin 点击登录 忘记密码可长按路由器重置键
  • rust入门材料清单

    rust book rustbook 配套视频教程 cargo 文档 crate io 标准库api 官方资料索引 rust 编程规范
  • js实现Math.sqrt()方法

    之前面试的时候 面试有一道题 要记算10的平方根 并且精确到0 01 我也是想了一会才想到了一种简单粗暴的方法 也算是完成了 squareRoot num gt let s 1 d 0 1 x 0 01 while s s
  • MyEclipse 8.0 中vssplugin的安装

    今天试用了myeclipse8 0 多了很多新特性 挺不错的 由于本司用的是vss库 所以vssplugin是必装项 可是安装的时候发布目录结构有所变动与myeclipse6 0有所区别 具体安装详见如下步骤 1 下载vss plugin
  • Python画爱心——谁能拒绝用代码敲出来会跳动的爱心呢~

    还不快把这份浪漫拿走 节日就快到来了 给Ta一个惊喜吧 今天给大家分享一个浪漫小技巧 利用Python中的 HTML 制作一个立体会动的心动小爱心 成千上百个爱心汇成一个大爱心 从里到外形成一个立体状 给人视觉上的冲击感 浪漫极了 V hw
  • div页面垂直居中方法方法

    基本思路 1 首们需要position absolute 绝对定位 而层的定位点 使用外补丁margin负值的方法 负值的大小为层自身宽度高度除以二 例子 一个层宽度是400 高度是300 使用绝对定位距离上部与左部都设置成50 而marg
  • 带你详细了解ADSS光缆

    ADSS 全介质自承式光缆 光缆是一种自支撑架空光缆 专为架空安装和部署而设计 适用于各种户外应用 本文将提供ADSS光缆的一些知识 什么是ADSS光缆 ADSS 光缆是一种光缆 其强度足以在结构之间支撑自身 而无需使用导电金属元件 该光缆
  • 创建qml自定义视频源(Qt5.15.2+设备帧)

    前言 若是看过笔者之前的文档 应该会注意到 笔者显示自定义视频 使用的是QQuickImageProvider和Image类型实现 本次笔者记录另一种显示方式 创建视频源 然后使用VideoOutput显示 因为Qt5和Qt6多媒体模块发生
  • QML自定义模块及qmldir的使用

    前言 在开发QtQuick项目中 当项目文件很多的情况下 可能会分成多级文件夹来进行分类 还有一些通用类型文件 如公共组件 通用配置等等 需要在各个不同的文件中进行调用 这种情况下 一种方式是在当前需要引用的文件中通过关键字import 加
  • TCP-三次握手

    文章目录 三次握手 简单示意图 详细分析 一些思考 为什么是三次握手 SYN 攻击 什么是SYN 攻击 如何防止SYN 攻击 数据包丢失了该怎么办 初始序列号为什么随机产生 为什么 SYN 段不携带数据却要消耗一个序列号呢 每次握手可以确定