TCP 协议简记 01 - TCP 包格式 连接管理

news2024/11/28 14:44:19

最近对 TCP 协议做了一次系统性的学习,种巨复杂的知识,只有系统性的总结归纳并且不断的实践才能够真正的掌握。后续会分为几篇文章来对 TCP 协议进行系统性的总结,帮助自己更好的理解 TCP 协议,也希望能够帮助到和我一样被 TCP 弄得头大的同学。

本篇 blog 主要对 TCP 协议的一些基本概念进行简单的介绍,包括 TCP 包格式、TCP 连接管理、TCP 状态机等。

TCP 协议简介

TCP 协议是面向连接的、可靠的、面向字节流的传输层协议,起源于 ARPANet 使用的 Network Control Protocol (NCP) 协议,为了改善该协议的一些问题工程师们又开发出了 Internet Transmission Control Program 程序来进行数据的传输。这是 TCP/IP 协议的前身,该程序的问题在于将网络层和传输层的功能合在了一起,其强制要求所有要使用网络层功能的应用必须使用传输层的功能,违反了分层、模块化设计的原则。

为了改善 TCTP 存在的问题,经过 3 个版本的演进,终于在第 4 个版本将网络层和传输层彻底分开,从而形成了 IPv4 协议和 TCP 协议。TCP 协议在 RFC 791 ( 2022 年 8 月发布了最新的 RFC9293 已经取代了 RFC791。)中进行了定义,不过在 RFC791 中并不包含所有的细节,因此后来有有了众多补充性的 RFC。

在这里插入图片描述

图片来自 TCP/IP Guide

TCP Segment 格式

首先我们先对 TCP 包进行一个简单的介绍,TCP 数据包也叫 Segment,因为 TCP 是面向字节流的传输,在 TCP 协议看来,应用发过来的数据就是一个个的字节,TCP 协议会将这些字节切分成一个个的 Segment 然后进行传输。

下图是 TCP 包的数据格式
在这里插入图片描述

图片来自 TCP/IP Guide

Segment 中各个字段含义:

字段含义简介
Source Port源端口发送端口
Destination Port目标端口接收端口
Sequence Number序列号TCP 协议会为被传输的每个字节标注序列号,用于接收端进行确认和数据重组
Acknowledgment确认号
Data Offset头部长度TCP 根据该字段来区分 Segment 包的头部和数据部分
Reserved保留位
Control Bits控制位标识信息的类型,比如 ACK 表示确认信息,SYN 表示建立连接信息等
Window Size窗口大小表示发送端的接收窗口大小,用于流量控制
Checksum校验和用于校验 TCP 头部和数据部分是否有错误
Urgent Pointer紧急指针用于指示紧急数据的位置
Options可选项
Padding填充字段用于保证 TCP 头部长度为 32 位的整数倍
Data应用数据
  • TCP 使用源端口与目标端口以及 IP 层的源 IP 和目标 IP 一起组成的四元组(sourceIP,sourcePort,destIP,destPort )来唯一标识一个连接,该四元组也被称为 Socket。
  • Reserved 最开始为 6 位,但是后来只有 4 位了,有两位被用作了 Control Bits 标识 CWR 和 ECE 两个控制位。

对于 Control Bits,该字段有 6 bit,每个 bit 代表一种消息类型,当该 bit 设置为 1 时表示启用,6 种消息类型如下:

BitNameDescription
0FIN结束连接
1SYN发起一个连接
2RST重置连接
3PSH接收方应该尽快将数据交给应用
4ACK确认号有效
5URG紧急指针有效
CWR拥塞窗口减小
ECE拥塞窗口减小

除了上述固定的字段外,TCP 还支持若干可选项用来实现特定的功能,可选项大致分为两类:

  • 不携带数据的可选项:option 仅包含 kind 字段,占 1 字节
  • 携带数据的可选项:格式固定为三部分:
    • Kind:可选项类型
    • Length: 可选项长度,单位字节
    • Data: 可选项的字段值

以下是一些常用的可选项,如果对于其他可选项感兴趣可以参考 Transmission Control Protocol (TCP) Parameters,该文章列出了所有的 Options 及其 RFC。

KindLengthMeaningDescription
0-End of Option List当 Option 列表结尾 TCP Header 结尾不重合时,会在 option 列表最后添加该 option 表示 Option 列表结束
1-No-Operation
24Maximum Segment Size确定 Segment 最大携带的数据大小
33Window Scale窗口缩放因子,用于扩大窗口大小,用于高速网络
42SACK Permitted用于启用 SACK 选项
5variableSACK用于启用 SACK 选项
143TCP Alternate Checksum Request (obsolete)用用于启用 TCP 备用校验和算法
15variableTCP Alternate Checksum Data (obsolete)用于启用 TCP 备用校验和算法

以上是对 TCP 包的介绍,对于各个字段先大致了解即可,后面会对这些字段进行详细的介绍。

TCP 连接 & 状态机

了解了 TCP 包的格式后,就可以对 TCP 的各种工作机制进行分析了。首先来看看 TCP 的连接建立和终止过程。

我们知道 TCP 是面向连接的传输协议,在传输数据之前收发双方必须先建立连接。所谓的连接并不是通信双方之间真有一条线路将双方连起来,而是双方维护了一系列的状态数据。比如序列号、发送窗口、SACK/CheckSum 算法等选项。通过这些状态,收发双发来判断数据包是否被接收到,是否需要重传,是否需要进行拥塞控制。而建立连接的过程就是同步这些状态信息,为数据发送做准备的过程。

TCP 通过 FSM(finite state machine) 有限状态机来管理连接的状态,其状态转换图如下。

在这里插入图片描述

图片来自 《TCP/IP Guide》

TCP 连接建立和终止过程以及数据传输过程如图:

在这里插入图片描述

图片来自 CoolShell

下面我们详细分析下 TCP 连接的建立和终止过程。

TCP 建立连接

1. 连接建立流程

TCP 采用“三次握手”协议来建立连接,所谓三次握手就是收发双方需要进行三次通信。其通信过程如图:

在这里插入图片描述
图片来自《TCP/IP Guide》

建立过程如下:

  • Server 启动进程,监听端口,进入 Listen 状态
  • Client 发送 SYN 信息,表示请求建立连接,进入 SYN_SENT 状态
  • Server 收到 SYN 信息,并将自己的 SYN 和 ACK 一同发送给 Client,进入 SYN_RECEIVED 状态
  • Client 收到 SYN&ACK 信息,并向 Server 发送 ACK 信息,进入 Established 状态
  • 服务端收到 ACK 信息,进入 Established 状态
  • 连接建立成功

除了正常的三次握手,还会存在收发双方同时发起请求的情况,其连接建立过程如图:

在这里插入图片描述

图片来自 《TCP/IP Guide》

2. 为什么需要三次握手

正常情况下之所以需要三次握手,主要原因在于:

  • 收发双方同步数据:同步序列号、MSS 等信息。尤其是序列号,收发双发都需要向对方发送自己的序列号并确认收到了对方的序列号。因此理论上需要如图所示的 4 次通信才能完成数据同步,但中间的两次通信可以合并为一次,因此只需要三次通信即可完成数据同步。
    在这里插入图片描述

  • 防止重复连接: 根据 RFC9293 中的内容,三次握手最重要的目的是避免历史旧连接重复建立,防止建立错误连接,为此 TCP 提供了一个 RST 的控制位,表示中止连接。

The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
— RFC9293

下面是 RFC 9293 中给出的一个三次握手时历史连接导致重置连接的例子:

在这里插入图片描述

图片来自 RFC 9293

我们来分析下上图中的过程:

A 向 B 发送了 SYN 消息,与此同时,之前丢失的一条 SYN 消息也发送给了 B。B 收到历史消息后返回 ACK,值为 SEQ + 1,A 会判断 B 返回的 ACK 是否正确:

  • 如果 B 返回的 ACK 不正确,则 A 知晓 B 响应的是历史连接,A 会直接发送 RST 消息来中止连接。
  • 如果 B 返回的 ACK 正确,则 A 向 B 发送 ACK 消息,双方连接建立成功。

因此除了 A 的第一次 SYN 请求外,发送方 A 还需要根据 B 的 ACK 消息来确认 B 是否接收到了正确的 SYN 信息并返回处理结果是中止连接还是建立连接,该过程最少需要三次通信,这是 TCP 使用三次握手的最主要原因。

TCP 终止连接

TCP 连接的的终止过程是一个双向的过程,即双方都可以主动发起终止连接的请求,因此 TCP 的连接终止过程是一个四次挥手的过程。

在这里插入图片描述

图片来自 《TCP/IP Guide》

连接终止过程为:

  • Client 发送 FIN 消息,表示不再发送数据,请求关闭连接,进入 FIN_WAIT_1 状态。此时 TCP 连接处于半关闭状态,即 Client 可以接收数据但是不能发送数据。
  • Server 收到 FIN 消息后,发送 ACK 消息,表示收到了 Client 的关闭请求,进入 CLOSE_WAIT 状态。此时 TCP 连接处于半关闭状态,即 Server 可以发送数据但是不能接收数据。
  • Client 收到 ACK 消息后,进入 FIN_WAIT_2 状态。
  • Server 端应用执行完毕,发送 FIN 消息,请求关闭连接,进入 LAST_ACK 状态。
  • Client 收到 FIN 消息后,发送 ACK 消息,表示收到了 Server 的关闭请求,进入 TIME_WAIT 状态。此时 TCP 连接处于半关闭状态,即 Client 可以接收数据但是不能发送数据。
  • Server 收到 ACK 消息后,进入 CLOSED 状态,此时 TCP 连接关闭。

如果是双方同时断开连接,过程如图:
在这里插入图片描述

了解了 TCP 建立连接的建立和终止过程,我们再来看下一些细节问题。

其他相关处理

1.选择初始序列号

TCP 通过序列号来标识数据包,序列号的初始值是随机的,三次握手的过程中,双方会交换自己的初始序列号(ISN,Initial Sequence Number),以便后续数据包的发送。

RFC9293 规定序列号是一个 32 位的定时计数器,每隔 4ms 会对计数器加 1,因此 ISN 的增长速度为 1/250s,即每秒 250 个。ISN 的范围为 0~2^32-1,即 0~4294967295,超过这个范围后会重新从 0 开始计数,大约 4.55 小时会重复一次。

之所以采用定时计数器的原因是避免来自不同连接的包发生混乱。如果每次建立连接时都从 1 开始计数,假设一个连接在断开后,又建立了一个新的连接,那么新连接的序列号可能会与之前的连接的序列号重复,这样就会导致数据包的混乱。如果是采用定时计数器,对于不同连接,每 4.55 小时才会重复一次,远远超过了段存活时间(Maximum Segment Lifetime)因此不会出现不同连接出现重复 ISN 的情况。。

但是基于定时计数器的 ISN 有两个问题:

  • 序列号可预测:由于基于定时计数器的序列号是每 4ms 加 1,攻击者可以通过分析 ISN 来伪造数据包,从而进行攻击。
  • 可快速耗尽:序列号范围是 0~4294967295,并且 1 个字节占用 1 个序列号,在高速网络下序列号会快速耗尽。在 1Gb/s 网速下序列号的耗尽时间为 34s ,而在 10Gb/s 网速下序列号的耗尽时间为 3s,100Gb 下只有 1/3s。

对于序列号可预测的问题,可以通过随机函数来初始化序列号。RFC6528 给出了如下随机函数:

ISN = M + F(localip, localport, remoteip, remoteport, secretkey)

其中 M 是一个计数器,F 是一个随机函数,localip、localport、remoteip、remoteport 是本地和远程的 IP 和端口,secretkey 是一个密钥,该密钥只有本地和远程双方知道,通过上述随机函数计算出的 ISN 是不可预测的。

对于序列号耗尽的问题,RFC7323 提出了TimeStamp Options 来解决。

2.确定 MSS

建立连接时,在 SYN 消息中还会在 Options 的携带 MSS(Max Segment Size) 信息,表示 TCP 连接双方能够接收的最大数据包大小(仅表示数据大小,不包含 header)

设置该字段的主要目的是防止 Segment 过大导致 IP 包分片,从而影响传输性能,同时为了提高 TCP 的传输效率,一般是在不超过 MTU 的情况下越大越好。

MSS 只能在建立连接时通过 SYN 消息传递,因为 TCP 的数据包是有大小限制的,如果在连接建立后,双方想要改变 MSS,那么只能重新建立连接。

如果 SYN 消息中没有 MSS 信息,则一般采用默认值 536 byte(默认 MTU 576 - IP Header 20 - TCP Header 20)

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

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

相关文章

STM32MP157驱动开发——LED驱动(设备树)

文章目录 设备树驱动模型如何使用设备树写驱动程序设备树节点要与 platform_driver 能匹配设备树节点指定资源,platform_driver 获得资源 LED 模板驱动程序的改造:设备树驱动模型修改设备树,添加 led 设备节点修改 platform_driver 的源码编译…

【论文阅读】聚集多个启发式信号作为监督用于无监督作文自动评分

摘要 本文提出一个新的无监督的AES方法ULRA,它不需要真实的作文分数标签进行训练;ULRA的核心思想是使用多个启发式的质量信号作为伪标准答案,然后通过学习这些质量信号的聚合来训练神经自动评分模型。为了将这些不一致的质量信号聚合为一个统…

springboot 多数据源配置

1.引入相关pom文件 <!-- spring boot 启动 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><artifactId>log4j-api</artifactId&…

7.5Java EE——Bean的装配方式

一、基于XML的装配 两种基于XML的装配方式 在基于XML的装配就是读取XML配置文件中的信息完成依赖注入&#xff0c;Spring容器提供了两种基于XML的装配方式&#xff0c;属性setter方法注入和构造方法注入。下面分别对这两种装配方式进行介绍。 a.属性setter方法注入 属性sett…

Vuex 数据共享

文章目录 前言Vuex项目的创建state 配置项getters 配置项mutations 配置项actions 配置项 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 体现数据共享的概念 所有组件都可以使用那数据 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可…

时序数据库 TDengine 与金山云两大产品完成兼容互认证

万物互联时代&#xff0c;企业数字化转型和政企上云如火如荼。在云计算迎来重大发展机遇的同时&#xff0c;数据库在企业数字化转型中也扮演着重要的角色——随着业务量的激增&#xff0c;数据库的弹性扩容、容灾备份等需求逐渐显现&#xff0c;在此挑战下&#xff0c;时序数据…

前端学习记录~2023.7.17~CSS杂记 Day9

前言一、浮动1、使盒子浮动起来2、清除浮动3、清除浮动元素周围的盒子&#xff08;1&#xff09;clearfix 小技巧&#xff08;2&#xff09;使用 overflow&#xff08;3&#xff09;display: flow-root 二、定位1、定位有哪些2、top、bottom、left 和 right3、定位上下文4、介绍…

jupyter notebook更换虚拟环境(内核)

jupyter notebook更换虚拟环境&#xff08;内核&#xff09; 创建一个新的虚拟环境 # stk_env 虚拟环境的名字&#xff0c;任取。 conda create -n stkenv python3.9激活虚拟环境 conda activate stkenv安装ipykernel # 为该虚拟环境&#xff0c;安装内核。 conda install -c a…

rabbitmq模块启动报java.net.SocketException: socket closed的解决方法

问题 最近在接手一个项目时&#xff0c;使用的是spring-cloud微服务构架&#xff0c;mq消息消费模块是单独一个模块&#xff0c;但启动这个模块一直报如下错误&#xff1a; java.net.SocketException: socket closed 这个错误是这个模块注册不到nacos报的错&#xff0c;刚开…

FCOS 论文学习

1. 解决了什么问题&#xff1f; 之前的目标检测器如 RetinaNet、SSD、YOLOv3 都依赖于 anchors。基于 anchors 的检测器有如下三个缺点&#xff1a; 检测表现对于 anchors 的大小、宽高比和数量等超参数很敏感&#xff1b;即使精心设计了 anchors&#xff0c;但由于大小和宽高…

架构训练营学习笔记:4-2 存储架构模式之复制架构

高可用的关键指标 问题&#xff1a;分为故障跟灾难。不是有了多活架构就不在用复制架构 &#xff0c;还是之前的合适原则&#xff1a;多活架构的技术复杂度 跟成本都比复制架构高。 高可用的关键指标 恢复时间目标(RecoveryTimeObjective&#xff0c;RTO)指为避免在灾难发生后…

rabbitmq部署(docker方式)

前言&#xff1a;rabbitmq一旦有漏洞&#xff0c;版本升级麻烦&#xff0c;于是改为docker部署 环境&#xff1a;centos7 #停掉之前的服务 systemctl stop rabbitmq-server systemctl disable rabbitmq-server 查了官网&#xff0c;当前3.11.x 最高版本是3.11.19, 虽然3.12…

【开源分享】在线客服系统源代码-thinphp网站在线客服系统源码(附源码完整搭建教程)...

本文的核心是一个多国语言在线客服聊天系统源码。我们将在这里保持非常简单。 这是一款旧版本的PHP客服源码。 基于ThinkPHP5 workerman&#xff0c;整体架构比较老&#xff0c;PHP客服端以及界面等需要在php-fpm下运行&#xff0c;即时通讯websocket服务端需要命令行执行。 源…

N-gram模型学习

网上有很多比较细节比较复杂比较清晰的介绍&#xff0c;我这里就不再细细的描述了&#xff0c;之前看文献的时候看到了这个模型&#xff0c;脑子里又没有印象&#xff0c;结果发现是python的学习范畴。 总的来说&#xff0c;这是一种文字&#xff0c;甚至可以上升到符号关联性…

基于Python的工业图像异常检测基础技术详解

引言 博文字数7000&#xff0c;建议阅读时间20分钟。 这篇博客对当前几种典型的图像异常检测算法进行了比较&#xff0c;包括Kmeans、Kmeans以及大津法&#xff08;OTSU&#xff09;&#xff0c;并给出了相关的代码实现与测试方法。总结的比较结果如下表所示&#xff1a; 方…

cocosCreator 3.6以上接入腾迅Bugly 捕捉JS错误 Android

cocosCreator3.6以上接入Bugly上报其实很简单&#xff0c;不需要网上那么多弯弯绕&#xff0c;三须三步走。 1. 按照官网方式接入android的bugly 2. android端写一个Bugly上报管理类 3. 修改你工程目录下native\engine\common\Classes\目录下的Game.h, Game.cpp两个文件&…

发电厂主厂房智能照明控制系统的设计和应用

摘要&#xff1a;当前&#xff0c;电厂主厂房的照明规模较大&#xff0c;而且具有许多回路&#xff0c;增加了电厂照明负荷&#xff0c;导致照明过程中的能源消耗较高。对此&#xff0c;电厂需要合理设计智能照明系统&#xff0c;运用智能技术提高电厂照明的运行管理水平&#…

如何在化工行业运用IPD?

化工行业作为国民经济的重要基础性行业&#xff0c;包含数以万计的产品种类&#xff0c;各具有不同的物理化学特性。化工产品的消费同国民经济状况联系非常紧密&#xff0c;主要去向广泛分布于基建、房地产、农业、汽车、服装等国民经济各个领域。按应用领域划分&#xff0c;典…

PCA与SVD

PCA流程&#xff1a; 当数据维度大时&#xff0c;构建协方差矩阵并求其特征值、特征向量会导致计算量大。所以可以利用SVD求解。 PCA算法的优化目标就是: ①降维后同一维度的方差最大。 ②不同维度之间的相关性为0。 根据线性代数&#xff0c;我们可以知道同一元素的协方差就…

Django项目开发快速入门

Django项目开发快速入门 生成Django项目编写module后台管理系统admin自定义管理页面视图函数使用Django模板 生成Django项目 现在cmd中使用命令安装Django框架 pip install django3.2使用命令生成项目 django-admin startproject DjStore使用命令生成应用 python .\manage.…