传输层协议TCP (上)
文章目录
- 前言
- TCP报文格式
- TCP连接管理
- 连接建立与中止
- 三次握手
- 三次握手的状态变化
- 为什么是三次握手
- 四次挥手
- 四次挥手的状态变化
- FIN_WAIT_2 状态可能导致连接长时间不释放的问题
- TIME_WAIT状态作用
- 复位报文段
- 非法连接请求
- 其他异常情况
- 半打开连接
- 同时握手
- 同时关闭
- 参考资料
前言
TCP(Transmission Control Protocol,传输控制协议)是互联网最重要的协议之一,为应用层提供可靠的、面向连接的数据传输服务。它广泛应用于 HTTP、FTP、SMTP 等协议中,保障数据能够准确、有序地到达目标设备。本文将主要介绍TCP连接管理机制
TCP报文格式
首先我们来看TCP的报文格式

- 16位源端口/目的端口 : 用于寻找发端和收端应用进程。这两个值加 上 IP 首部中的源端 IP 地址和目的端 IP 地址唯一确定一个 TCP 连接。
- 序号 : 序号用来标识从 TCP 发端向 TCP 收端发送的数据字节流,它表示在这个报文段中的的第一 个数据字节。
- 确认序号 : 确认这个序号以前的报文都收到了, ACK标记为 1 生效
- 4位首部长度 : 表示该TCP头部有多少个32位bit(有多少个4字节), 首部长度范围[5,15], 所以TCP报头长度[20,60]字节
- 6个标注位
- URG : 紧急指针有效
- ACK : 确认序号有效
- PSH : 提示接收方应该尽快将这个报文交付到应用层
- RST : 直接终止当前连接或拒绝新的连接请求, 我们把携带 RST 标识的称为复位报文段
- SYN : 请求建立连接; 我们把携带 SYN 标识的称为同步报文段
- FIN : 通知断开连接, 我们称携带 FIN 标识的为结束报文段
- 16位窗口大小 : 自己的接收缓冲区的剩余空间大小
- 16位校验和 : CRC校验, 接收端校验不通过, 则认为数据有问题
- 16位紧急指针 : 标识哪部分数据是紧急数据
TCP连接管理
TCP 是一个面向连接的协议。无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接
连接建立与中止
我们使用tcpdump工具来查看TCP在连接建立和中止时发生了什么, 这里使用了telnet向一个服务端发起连接
localhost.57692 > localhost.http-alt:
Flags [S], cksum 0xfe30 (incorrect -> 0xe677), seq 2011543754, win 65495, options [mss 65495,sackOK,TS val 3010364542 ecr 0,nop,wscale 7], length 0localhost.http-alt > localhost.57692:
Flags [S.], cksum 0xfe30 (incorrect -> 0xaee7), seq 2821871467, ack 2011543755, win 65483, options [mss 65495,sackOK,TS val 3010364542 ecr 3010364542,nop,wscale 7], length 0localhost.57692 > localhost.http-alt:
Flags [.], cksum 0xfe28 (incorrect -> 0xd5a3), seq 1, ack 1, win 512, options [nop,nop,TS val 3010364542 ecr 3010364542], length 0localhost.57692 > localhost.http-alt:
Flags [F], cksum 0xfe28 (incorrect -> 0xc7a7), seq 1, ack 1, win 512, options [nop,nop,TS val 3010368121 ecr 3010364542], length 0localhost.http-alt > localhost.57692:
lags [.], cksum 0xfe28 (incorrect -> 0xb9a9), seq 1, ack 2, win 512, options [nop,nop,TS val 3010368124 ecr 3010368121], length 0localhost.http-alt > localhost.57692:
Flags [F], cksum 0xfe28 (incorrect -> 0xae2d), seq 1, ack 2, win 512, options [nop,nop,TS val 3010371063 ecr 3010368121], length 0localhost.57692 > localhost.http-alt:
Flags [.], cksum 0xa2af (correct), seq 2, ack 2, win 512, options [nop,nop,TS val 3010371063 ecr 3010371063], length 0
主要观察这些标记位变化, 可以得出
- 建立连接
- 客户端 --> 服务端发送带有SYN标识的报文
- 服务端 --> 客户端发送SYN+ACK
- 客户端 --> 服务端发送ACK
- 关闭连接
- 客户端 --> 服务端发送带有FIN标识的报文
- 服务端 --> 客户端发送ACK
- 服务端 --> 客户端发送FIN
- 客户端 --> 服务端发送ACK
有时我们也可以看到在服务端 --> 客户端 合并了FIN+ACK报文
localhost.http-alt > localhost.57692:
Flags [F.] ......
三次握手
从上面的例子来看, 为了建立一TCP条连接
- 请求端(通常称为客户端)发送一个 SYN 段指明打算连接的服务器的端口,
- 服务器发回 SYN 报文段作为应答。同时,对客户的 SYN 报文段进行确认。
- 客户将对服务器的 SYN 报文段进行确认。
这三个报文段完成连接的建立。这个过程也称为三次握手
三次握手的状态变化

- 一开始, 客户端和服务端都处于CLOSED状态, 然后服务端开始监听进入LISTEN状态
- 客户端发起请求建立连接, 发送一个带有SYN标识的报文, 客户端进入SYN_SEND状态
- 服务端收到客户端发送的SYN报文, 回应一个SYN+ACK, 服务端进入SYN_RCVD状态
- 客户端收到服务端的SYN+ACK, 回应一个ACK, 客户端三次握手完成, 进入ESTABLISHED状态
- 服务端收到客户端的ACK后, 服务端三次握手完成, 也进入ESTABLISHED状态
为什么是三次握手
TCP 是一个全双工协议,这意味着连接的双方可以同时发送和接收数据。为了确保这种能力,在连接建立时,必须确认双方都能够发送和接收数据, 三次握手可以保证双方可读可写
如果是二次握手, 客户端在接收到服务端发送的ACK+SYN就已经结束了, 服务端无法得知客户端是否收到此报文, 也就是不能保证客户端是否可以接收数据, 如果服务端发送的ACK+SYN发送丢包, 此时服务端认为连接建立完成, 但实际并没有, 客户端和服务端各自等待对方的响应,最终会导致超时和连接失败
三从握手是可以满足这些条件的最小次数, 三此握手可以确定双方的全双工, 如果任意时刻发生丢包, 也能通过超时重传来机制来保证
四次挥手
建立一个连接需要三次握手,而终止一个连接要经过 4次握手, 从之前的例子来看
- 客户端发送一个FIN标识的报文表示要和服务端关闭连接
- 服务端应答一个ACK
- 服务端发送FIN表示与客户端关闭连接
- 客户端应答一个ACK
四次挥手的状态变化

- 客户端打算关闭连接, 发送一个FIN报文, 客户端进入FIN_WAIT_1状态
- 服务端应答一个ACK, 服务端进入CLOSE_WAIT状态
- 客户端收到服务端的ACK, 客户端进入FIN_WAIT_2状态
- 服务端打算关闭连接, 发送一个FIN报文, 服务端进入LAST_WAIT状态
- 客户端应答一个ACK, 客户端进入TIME_WAIT状态
- 服务端收到应答, 服务端进入CLOSED状态
- 客户端会在2MSL(Maximum Segment Lifetime 最大报文生命周期)后自动关闭, 进入CLOSED状态
FIN_WAIT_2 状态可能导致连接长时间不释放的问题
在 FIN_WAIT_2 状态我方已经发出了 FIN ,并且另一端也已对它进行确认。除非我们在实行半关闭,否则将一直等待另一端的应用层意识到它已收到一个文件结束符说明,并向我们发一 个 FIN 来关闭另一方向的连接。只有当另一端的进程完成这个关闭,我们这端才会从 FIN_WAIT_2 状态进入 TIME_WAIT 状态。 这意味着我们这端可能永远保持这个状态。另一端也将处于 CLOSE_WAIT状态,并一直保持这个状态直到对方关闭连接
某些操作系统(如 Linux)提供了超时机制,当连接在 FIN_WAIT_2状态超过一定时间后,内核会强制关闭连接,释放资源。在 Linux 中,可以通过修改 TCP 超时参数 来限制 FIN_WAIT_2 的最大存活时间
TIME_WAIT状态作用
TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个 MSL(maximum segment lifetime)的时间后才能回到CLOSED状态
查看MSL时间
$ cat /proc/sys/net/ipv4/tcp_fin_timeout
60
MSL 是任何报文段被丢弃前在网络内的最长时间, 等待2MSL时间可以保证一些陈旧报文已经消散, 同时TIME_WAIT状态依然可以接收对方的重传报文,并进行必要的应答
如果没有这个状态的等待时间, 假设我们主动关闭的一方关闭后立即重启, 端口不变, 那么就有可能将一些还在网络中的陈旧报文接收到, 造成曲解, 如果客户端最后应答的ACK报文丢包, 在2MSL时间内也可以进行重传
复位报文段
TCP 首部中的 RST 比特是用于“复位”的。一般说来,无论何时一个报文段发往基准的连接(referenced connection)出现错误,TCP 都会发出一个复位报文段 ------《TCP/IP详解 卷1: 协议》
非法连接请求
当一个数据报到达目的端口时,该端口没在使用,这是一个非法连接请求, TCP 使用复位。我们来查看Linux2.6内核源码方便理解这点
TCP对数据包的处理在tcp_v4_rcv中
/* 处理接收到的TCP数据包 */
int tcp_v4_rcv(struct sk_buff *skb)
{......
no_tcp_socket: /* 没有找到对应的socket,发送RST */if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) /* 如果不符合安全策略,丢弃 */goto discard_it;if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) { /* 如果数据包长度或校验和有问题,丢弃 */
bad_packet:TCP_INC_STATS_BH(TCP_MIB_INERRS);} else {tcp_v4_send_reset(skb); /* 发送RST */}discard_it:/* 丢弃数据包 */kfree_skb(skb);return 0;......
}
然后调用tcp_v4_send_reset发送复位报文
static void tcp_v4_send_reset(struct sk_buff *skb)
{struct tcphdr *th = skb->h.th;struct tcphdr rth;struct ip_reply_arg arg;......memset(&rth, 0, sizeof(struct tcphdr));rth.dest = th->source;rth.source = th->dest;rth.doff = sizeof(struct tcphdr) / 4;rth.rst = 1;//设置RST标志if (th->ack) {rth.seq = th->ack_seq;} else {rth.ack = 1;rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin +skb->len - (th->doff << 2));}memset(&arg, 0, sizeof arg);arg.iov[0].iov_base = (unsigned char *)&rth;arg.iov[0].iov_len = sizeof rth;arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,skb->nh.iph->saddr, /*XXX*/sizeof(struct tcphdr), IPPROTO_TCP, 0);arg.csumoffset = offsetof(struct tcphdr, check) / 2;ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
}
我们可以看到 RST 标注位被设置
其他异常情况
-
连接中断:当连接的另一端在未正常关闭的情况下强制终止连接(比如程序崩溃或网络故障),接收方可能会发送 RST 报文来终止连接。
-
协议错误或违规行为:当发现协议中的违规行为(例如,接收到错误的序列号、非法的报文等),接收方可以使用 RST 报文来重置连接
半打开连接
如果一方已经关闭或异常终止连接而另一方却还不知道,我们将这样的 TCP 连接称为半打开连接, 半打开连接的常见原因是当客户主机突然掉电或者结束客户应用程序异常中止后再关机, 只有这条连接上没有数据传递, 服务端就不会知道客户端已经关闭, 当客户端再次打开后又会重新建立连接, 长期以往就会出现连接堆积问题, 后面我们介绍TCP的保活机制可以解决这个问题
同时握手
当两端同时向对方发送 SYN 请求以建立 TCP 连接时,这种情况被称为 SYN Flood 的一种特殊形式,或者更正式地叫做 双向 SYN 同时发起。这种情形会引起连接的同时握手(Simultaneous Open)
TCP标准支持这种同时握手, 对于同时打开仅建立一条连接而不是两条连接, 状态转移更像双向的三次握手, 一共要交换四个报文

- 两端同时发起请求建立连接, 发送一个带有SYN标识的报文, 都进入SYN_SEND状态
- 两端收到对方发送发送的SYN报文, 回应一个SYN+ACK, 都进入SYN_RCVD状态
- 两端收到对方的SYN+ACK, 握手完成, 进入ESTABLISHED状态
同时关闭
既然同时握手可能存在, 那么双方都执行主动关闭也是可能的, TCP 协议也允许这样的同时关闭(simultaneous close)
CLOSING状态就是为了处理这种特殊情况, 两端都已经发送了 FIN 包,但还未完全收到对方的确认包时

- 两端同时发送FIN报文表示关闭连接, 都进入FIN_WAIT_1状态
- 两端收到对方发送的FIN报文, 回应一个ACK, 两端进入CLOSING状态
- 两端收到对方的ACK后, 进入TIME_WAIT状态
参考资料
- 《TCP/IP详解 卷1: 协议》
- Linux2.6内核源码
相关文章:
传输层协议TCP (上)
文章目录 前言TCP报文格式TCP连接管理连接建立与中止三次握手三次握手的状态变化为什么是三次握手 四次挥手四次挥手的状态变化FIN_WAIT_2 状态可能导致连接长时间不释放的问题TIME_WAIT状态作用 复位报文段非法连接请求其他异常情况 半打开连接同时握手同时关闭 参考资料 前言…...
深度学习框架探秘|Keras:深度学习的魔法钥匙
一、引言:深度学习浪潮中的 Keras 前面的文章我们探秘了深度学习框架中的两大明星框架 —— TensorFlow 和 PyTorch 以及 两大框架的对比 在深度学习的众多框架中,还有一款框架备受开发者们的喜爱 —— Keras 。它就像是一位贴心的助手,为我…...
使用爬虫获取1688商品分类:实战案例指南
在电商领域,获取商品分类信息对于市场分析、选品决策和竞争情报收集至关重要。1688作为国内领先的B2B电商平台,提供了丰富的商品分类数据。通过爬虫技术,我们可以高效地获取这些分类信息,为商业决策提供有力支持。 一、为什么选择…...
MySQL常见错误码及解决方法(1130、1461、2003、1040、2000、1049、1062、1129、2002、1690等)
目录 【问题1】、FATAL: error 1130: Unknown error 1130 【问题2】、FATAL: error: 1461 【问题3】、ERROR 2003 (HY000): Cant connect to MySQL server on "" (113) 【问题4】、FATAL: error 2003: Cant connect to MySQL server on 172.19.111.151 (111) 【问…...
【k8s应用管理】kubernetes lngress资源管理
文章目录 补充**Service 的作用****Kubernetes 外部访问方案** Kubernetes IngressIngress 概述Kubernetes 外部访问方案对比Ingress 的组成**Ingress-Nginx 工作原理**Ingress 控制器的部署方式1. DaemonSet Host 网络模式2. Deployment NodePort/LoadBalancer Service 创建…...
2.11学习
misc buu-荷兰宽带泄露 下载附件得到了一个后缀为.bin的文件 是宽带数据文件,用RouterPassView工具进行查看。大多数现代路由器都可以让您备份一个文件路由器的配置文件,然后在需要的时候从文件中恢复配置。路由器的备份文件通常包含了像您的ISP的用户…...
Python 调用 DeepSeek API 案例详细教程
本案例为以 Python 为例的调用 DeepSeek API 的小白入门级详细教程 步骤 先注册并登录 DeepSeek 官网:https://www.deepseek.com/ 手机号验证码注册或登录即可 创建 API KEY 注意保存,写代码时必须提供的 打开 Pycharm 创建工程 并安装 OpenAI 库编写代…...
C++ Primer 函数基础
欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…...
qt QPlainTextEdit总结
QPlainTextEdit 概述 用途:专为处理纯文本设计,适合大文本编辑和简单文本显示(如日志、代码编辑器)。 特点:相比QTextEdit,轻量高效,支持快速加载和滚动大文件,默认不支持富文本。 …...
【SVN基础】
软件:ToritoiseSVN 代码版本回退:回退到上一个版本 问题:SVN版本已经提交了版本1和版本2,现在发现不需要版本2的内容,需要回退到版本1然后继续开发。 如图SVN版本已经提交到了107版本,那么本地仓库也已经…...
kron积计算mask类别矩阵
文章目录 1. 生成类别矩阵如下2. pytorch 代码3. 循环移动矩阵 1. 生成类别矩阵如下 2. pytorch 代码 import torch import torch.nn as nn import torch.nn.functional as Ftorch.set_printoptions(precision3, sci_modeFalse)if __name__ "__main__":run_code 0…...
【前端】【vue】vue2/3,nuxt的插槽使用详解
插槽在Vue2、Vue3和不同版本Nuxt中的使用 Vue2中的插槽 基础插槽 在Vue2中,基础插槽允许在组件的模板中定义一个占位符,然后在使用组件时插入自定义内容。例如,创建一个简单的MyBox组件: <template><div class"…...
Stable Diffusion 安装教程(附安装包) 【SD三种安装方式,Win+Mac一篇文章讲明白】
“Stable Diffusion的门槛过高、不会安装?没关系,这篇文章教会你如何安装!” Stable Diffusion的安装部署其实并不困难,只需简单点击几下,几分钟就能安装好,不管是windows还是苹果mac电脑,关于…...
网络安全用centos干嘛 网络安全需要学linux吗
网络安全为啥要学Linux系统,据不完全统计,Linux系统在数据中心操作系统上的份额高达70%。它一般运行于服务器和超级计算机上。 所以我们日常访问的网站后台和app后端都是部署在Linux服务器上的,如果你不会Linux系统操作,那么很多…...
使用Opencv方法进行模板匹配
1. 引言 模板匹配(Template Matching)是一种基于图像处理的模式识别技术,主要用于在目标图像中查找与给定模板最匹配的区域。它在目标检测、工业检测、机器人视觉等领域有广泛应用。本文将详细介绍传统图像处理方法实现模板匹配的基本原理、…...
jupyter notebook中3种读图片的方法_与_图片翻转(上下翻转,左右翻转,上下左右翻转)
已有图片cat.jpg 相对于代码的位置,可以用./cat.jpg进行读取。 下面是3种读图片的方法。 1.python读图片-pillow 图片文件不适合用open去读取 用open读图片,易引发UnicodeDecodeError: gbk codec cant decode byte 0xff in position 0: illegal multib…...
微软官方出品GPT大模型编排工具:7个开源项目
今天一起盘点下,12月份推荐的7个.Net开源项目(点击标题查看详情)。 1、一个浏览器自动化操作的.Net开源库 这是一个基于 Google 开源的 Node.js 库 Puppeteer 的 .NET 开源库,方便开发人员使用无头 Web 浏览器抓取 Web、检索 Ja…...
MongoDB 的批量查找符号
一、$in 操作符 1. 功能 $in 操作符用于匹配字段值等于指定数组中任意值的文档,能批量查找多个特定值的文档。 2. 语法示例 db.collection.find({ field: { $in: [value1, value2, ...] } }); 3. 代码示例 假设有个名为 users 的集合,里面存有用户…...
bash shell笔记——循环结构
0 引言 本文主要介绍linux bash shell循环结构的基本使用 1 测试环境 查看系统版本: uname -a : Ubuntu 18.04 查看bash版本: bash -version : GNU bash, version 4.4.20(1)-release 创建.sh文件: vim 00test.sh 修改00test.sh权限&…...
rpx和px混用方案
(1)创建一个全局的样式配置文件: // styles/variables.scss :root {// 基础字体大小--font-size-xs: 12px;--font-size-sm: 14px;--font-size-md: 16px;--font-size-lg: 18px;// 响应式间距--spacing-xs: 5px;--spacing-sm: 10px;--spacing-…...
解释下SpringBoot中的服务、依赖项、微服务、分布式的概念和关系
在Spring Boot中,服务、依赖项、微服务和分布式是常见的概念,它们之间的关系如下: 1. 服务(Service) 定义:服务是应用程序中处理业务逻辑的组件,通常封装了特定的功能。作用:服务层…...
机器视觉--Halcon变量的创建与赋值
一、引言 在机器视觉领域,Halcon 作为一款强大且功能丰富的软件库,为开发者提供了广泛的工具和算子来处理各种复杂的视觉任务。而变量作为程序中存储和操作数据的基本单元,在 Halcon 编程中起着至关重要的作用。正确地创建和赋值变量是编写高…...
ES常用查询
根据编号查询 GET custom/_search { "query": { "term": { "no": "abc" } } } 查询指定的列 GET custom/_search { "_source": ["id", "no"], "size": 10000, …...
数据库与表的基本操作
创建订货管理系统数据库。数据库名称为Ordering,其数据文件的逻辑名称为Ordering_Data,存放在C盘的Order文件夹下;日志文件的逻辑名称为Ordering_Log,存放在C盘的Order文件夹下。数据库中包含数据表,分别为数据表C&…...
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter12-BOM
十二、BOM 虽然 ECMAScript 把浏览器对象模型(BOM,Browser Object Model)描述为 JavaScript 的核心,但实际上 BOM 是使用 JavaScript 开发 Web 应用程序的核心。BOM 提供了与网页无关的浏览器功能对象。 HTML5 规范中有一部分涵盖…...
03【FreeRTO队列-如何获取任务信息与队列的动静态创建】
一.利用 vTaskList()以及 vTaskGetRunTimeStats()来获取任务的信息 1.现象与开启启用宏 freeRTOSConfig.h //必须启用 #define configUSE_TRACE_FACILITY 1 #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_STATS_FORMATTING_FUNCTIONS…...
GBD研究——美国州级地图(附资源)
美国州级别地图 地图源很多,随便下载。不过我试了两个资源,发现有的资源会漏掉阿拉斯加和夏威夷。 就剩大的这块佩奇 出现这样的问题,要么跟数据源有关,要么就是要掉地名来看,是不是没匹配上。 亲自试过,…...
【微服务学习一】springboot微服务项目构建以及nacos服务注册
参考链接 3. SpringCloud - 快速通关 springboot微服务项目构建 教程中使用的springboot版本是3.x,因此需要使用jdk17,并且idea也需要高版本,我这里使用的是IDEA2024。 环境准备好后我们就可以创建springboot项目,最外层的项目…...
第39周:猫狗识别 2(Tensorflow实战第九周)
目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 5.1 上次程序的主要Bug 5.2 修改版…...
【Elasticsearch源码解读】代码包结构概述
Elasticsearch的代码库包含多个包,每个包负责不同的功能。以下是这些包的主要功能: #### action 封装了Elasticsearch的各种操作,如索引、搜索、删除等,提供了与集群交互的接口。 #### bootstrap 包含启动Elasticsearch节点所…...
