TCP协议的RST标志
下文中的内容多数来自【参考】中的文章,这边进行一个整理和总结,后续会慢慢增加出现各个 RST 包的测试代码,便于理解。
TCP的 “断开连接” 标志
-
RST 标志
Reset,复位标志,用于非正常地关闭连接。它是 TCP 协议首部里的一个标志位。发送 RST 包关闭连接时,直接丢弃缓冲区的包并发送 RST 包,而接收端收到 RST 包后,也不必发送 ACK 包来确认。
TCP 套接字在任何状态下,只要收到 RST 包,即可进入 CLOSED 初始状态,不会有任何回应。至于是否通知上层应用,要根据应用程序是阻塞模式还是非阻塞模式:
- 阻塞模型下,内核无法主动通知应用层出错,只有应用层主动调用 read() 或者 write() 这样的 IO 系统调用时,内核才会利用出错来通知应用层对端 RST。
- 非阻塞模型下,select 或者 epoll 会返回 sockfd 可读,应用层对其进行读取时,read() 会报错 RST。
-
FIN 标志
发端完成发送任务标识。用来释放一个连接。FIN=1 表明此报文段的发送端的数据已经发送完毕,并要求释放连接。
-
RST 和 FIN 的区别
- 正常地关闭连接用 FIN 标志位,但 FIN 标志位不能用来处理异常情况;
- RST 会导致连接立即终止,而在 FIN 中会得到确认。
TCP 出现 RST 包的情况
-
连接未监听的端口
连接一个未监听的端口,则被连接方会发送一个 RST。也就是说主机传输层 TCP 程序接收到一个 SYN 包,而这个 SYN 包目的端口并没有 socket 监听,那么主机的协议栈会直接回复一个 RST。
-
向已关闭的连接发送数据
顾名思义,主机传输层 TCP 协议程序接收到一条 TCP 数据段,而目的端口并没有 socket 监听,那么主机的协议栈会直接回复一个 RST。
-
向已关闭的连接发送 FIN
主机传输层 TCP 协议程序接收到一条 FIN,而目的端口并没有 socket 监听,那么主机的协议栈会直接回复一个 RST。
-
向已经消逝的连接中发送数据
和上面的举例相同。
-
处理半打开连接
一方关闭了连接,另一方却没有收到结束报文(如网络故障),此时另一方还维持着原来的连接。而一方即使重启,也没有该连接的任何信息。这种状态就叫做半打开连接。而此时另一方往处于半打开状态的连接写数据,则对方回应 RST 复位报文。此时会出现 connect reset by peer 错误。详见下文测试代码。
-
目的主机或网络路径中的防火墙拦截
如果目的主机或者网络路径中显式的设置了对数据包的拦截,如使用 iptables 对主机的防火墙添加了一条规则,对于目的端口是 6000 的 TCP 报文,丢弃并回复 RST。
-
TCP 接收缓冲区 Recv-Q 中的数据未完全被应用程序读取时关闭该 socket
接收到的数据缓存在缓冲区 Recv-Q,它们等待被上层应用取走,如果缓冲区 Recv-Q 有数据未被应用取走,而此时调用 close 函数关闭 TCP 连接,那么 TCP 协议程序发送的就不是 FIN,而是 RST。此时会出现 Connection reset by peer 错误,详见下文测试代码。
-
请求超时后收到回复
主机创建 socket,设置 SO_RCVTIMEOUT 选项为100ms,向对端发送 SYN,超过100ms后才收到 ACK+SYN,那么主机的协议栈会直接回复一个 RST。
-
SO_LINGER
socket 设置 SO_LINGER 选项,socket 调用 close 函数时,会直接丢弃缓冲区 Send_Q 未发完的数据,并发送 RST。
-
Linux 下启用 TIME_WAIT 快速回收
修改 /etc/sysctl.conf 中内核参数:net.ipv4.tcp_tw_recycle = 1,当收到的 SYN 包的 timestamp 比上次的小时,就会发 RST。
-
移动链路
移动网络下,国内是有5分钟后就回收信令,也就是 IM 产品,如果心跳>5分钟后服务器再给客户端发消息,就会收到 RST。也要查移动网络下 IM 保持<5min 心跳。
-
GFW
防火长城(Great Firewall of China,简称GFW)是中国政府在互联网空间中发起的一项大规模干预措施,旨在审查并控制中国地区的互联网使用,以遏制虚假信息、不良内容和外部信息流入中国境内。防火长城被普遍认为是政府和监管机构利用技术工具监控国家居民上网行为的全球最大系统,而它的技术基础上,有多种关键的审查与监管工具,如域名解析服务(DNS)、网络流量检测和内容过滤系统(CFMS)等。
-
负载等设备
负载设备需要维护连接转发策略,长时间无流量,连接也会被清除,而且很多都不告诉两层机器,新的包过来时才通告 RST。
Apple push 服务也有这个问题,而且是不可预期的偶发性连接被 RST;RST 前第一个消息 write 是成功的,而第二条写才会告诉你连接被重置,
曾经被它折腾没辙,因此打开每2秒一次 tcp keepalive,固定5分钟 TCP 连接回收,而且发现连接出错时,重发之前10s内消息。
-
超过超时重传次数
-
seq 不正确
-
keepalive 超时
公网服务 tcp keepalive 最好别打开;移动网络下会增加网络负担,切容易掉线;非移动网络核心 ISP 设备也不一定都支持 keepalive,曾经也发现过广州那边有个核心节点就不支持。
-
数据错误,不是按照既定序列号发送数据
测试代码
-
上述第6种情况【TCP 接收缓冲区 Recv-Q 中的数据未完全被应用程序读取时关闭该 socket】
客户端测试代码:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h>int main(void) {int len;int sockFd;char sendBuf[256];struct sockaddr_in addr;bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);addr.sin_port = htons(8888);if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error");return -1;}if (connect(sockFd, (struct sockaddr *)&addr, sizeof(addr)) < 0){perror("connect error");close(sockFd);return -1;}memset(sendBuf, 0xFF, sizeof(sendBuf));send(sockFd, sendBuf, sizeof(sendBuf), 0);len = recv(sockFd, sendBuf, sizeof(sendBuf), 0);if (len >= 0){printf("len: %d\n", len);}else{printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno)); }close(sockFd);return 0; }
服务端测试代码:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h>int main(void) {int readLen;int sockFd;int clientFd;char recvBuf[128] = {0};struct sockaddr_in saddr;if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error");return -1;}bzero((void*)&saddr, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_addr.s_addr = htonl(INADDR_ANY);saddr.sin_port = htons(8888);if (bind(sockFd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind error");close(sockFd);return -1;}if (listen(sockFd, 5) < 0){perror("listen error");close(sockFd);return -1;}printf("accept waiting, sockFd: %d\n", sockFd);if ((clientFd = accept(sockFd, NULL, NULL)) == -1){perror("accept error");close(sockFd);return -1;}while (1){memset(recvBuf, 0, sizeof(recvBuf));readLen = recv(clientFd, recvBuf, sizeof(recvBuf), 0);if (readLen > 0){printf("readLen: %d\n", readLen);}else if (readLen == 0){printf("client fd is closed!\n");close(clientFd);break;}else {printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno));close(clientFd);break;}close(clientFd);break;}close(sockFd);return 0; }
服务端输出:
客户端输出:
wireshark 抓包结果:
该举例中,客户端发送256字节的数据到服务端,服务端只接收了128字节的数据就关闭了套接字,此时服务端的 TCP 接收缓冲区中还剩128字节未读取,所以服务端发送 RST 到客户端。
-
上述第5种情况【处理半打开连接】
客户端测试代码:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h>int main(void) {int len;int sockFd;char sendBuf[256];struct sockaddr_in addr;bzero(&addr, sizeof(addr));addr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);addr.sin_port = htons(8888);if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error");return -1;}if (connect(sockFd, (struct sockaddr *)&addr, sizeof(addr)) < 0){perror("connect error");close(sockFd);return -1;}memset(sendBuf, 0xFF, sizeof(sendBuf));send(sockFd, sendBuf, sizeof(sendBuf), 0);sleep(1);send(sockFd, sendBuf, sizeof(sendBuf), 0);close(sockFd);return 0; }
服务端测试代码:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <stdlib.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h>int main(void) {int readLen;int sockFd;int clientFd;char recvBuf[256] = {0};struct sockaddr_in saddr;if ((sockFd = socket(AF_INET, SOCK_STREAM, 0)) < 0){perror("socket error");return -1;}bzero((void*)&saddr, sizeof(saddr));saddr.sin_family = AF_INET;saddr.sin_addr.s_addr = htonl(INADDR_ANY);saddr.sin_port = htons(8888);if (bind(sockFd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind error");close(sockFd);return -1;}if (listen(sockFd, 5) < 0){perror("listen error");close(sockFd);return -1;}printf("accept waiting, sockFd: %d\n", sockFd);if ((clientFd = accept(sockFd, NULL, NULL)) == -1){perror("accept error");close(sockFd);return -1;}while (1){memset(recvBuf, 0, sizeof(recvBuf));readLen = recv(clientFd, recvBuf, sizeof(recvBuf), 0);if (readLen > 0){printf("readLen: %d\n", readLen);}else if (readLen == 0){printf("client fd is closed!\n");close(clientFd);break;}else {printf("[line:%d] errno: %d, strerror(errno): %s\n", __LINE__, errno, strerror(errno));close(clientFd);break;}close(clientFd);break;}close(sockFd);return 0; }
wireshark 抓包结果:
该举例中,客户端发送数据到服务端,服务端将数据接收后就关闭了套接字,随后,客户端又发送数据到服务端,因为此时服务端已将套接字关闭,所以服务端会发送 RST 到客户端。
参考
[1] https://zhuanlan.zhihu.com/p/361714600
[2] https://baijiahao.baidu.com/s?id=1632327385547303797&wfr=spider&for=pc
[3] https://www.cnblogs.com/JohnABC/p/6323046.html
[4] https://www.pianshen.com/article/8750375150/
相关文章:

TCP协议的RST标志
下文中的内容多数来自【参考】中的文章,这边进行一个整理和总结,后续会慢慢增加出现各个 RST 包的测试代码,便于理解。 TCP的 “断开连接” 标志 RST 标志 Reset,复位标志,用于非正常地关闭连接。它是 TCP 协议首部里…...

【软件质量与软件测试 白盒测试与黑盒测试】
第十章 黑盒测试 10.1 等价类划分: 10.1.1 划分等价类 等价类是指所有数据中的一组,它们具有相同的测试结果或相同的响应。等价类划分是将输入数据分为多个等价类的过程。 10.1.2 划分等价类的方法 划分等价类方法主要包括以下几种: 特…...

JavaScript教程(高级)
面向对象编程介绍 两大编程思想 (1)、 面向过程编程: (缩写 POP)( Process-oriented programming)面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现&am…...

C++进阶 —— 范围for(C++11新特性)
目录 一,范围for介绍 二,范围for注意事项 一,范围for介绍 范围for(range-based for loop)是C11新引入的特性,可遍历各种序列结构的容器(如数组、vector、list等);每次循…...

ELK +Filebeat日志分析系统
一、 ELK日志分析系统概述 1、ELK简介 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件。新增了一个FileBeat,它是一个轻量级的日志收集处理工具(Agent),Filebeat占用资源少,…...

万字解析PELT算法!
Linux是一个通用操作系统的内核,她的目标是星辰大海,上到网络服务器,下至嵌入式设备都能运行良好。做一款好的linux进程调度器是一项非常具有挑战性的任务,因为设计约束太多了: 它必须是公平的快速响应系统的throughp…...

腾讯云服务器端口怎么全开?教程来了
腾讯云服务器端口怎么全开?云服务器CVM在安全组中设置开通,轻量应用服务器在防火墙中设置,腾讯云百科来详细说下腾讯云服务器端口全开放教程: 目录 腾讯云服务器端口全部开通教程 云服务器CVM端口全开放教程 轻量应用服务器开…...

深入理解Java虚拟机:JVM高级特性与最佳实践-总结-13
深入理解Java虚拟机:JVM高级特性与最佳实践-总结-13 Java内存模型与线程Java内存模型原子性、可见性与有序性先行发生原则 Java内存模型与线程 Java内存模型 原子性、可见性与有序性 Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这三个特征来…...

租售keysight E8257D 50G模拟信号发生器 销售/回收
是德(Keysight) E8257D 模拟信号发生器 Keysight E8257D (Agilent) PSG 模拟信号发生器提供业界领先的输出功率、电平精度和高达 67 GHz 的相位噪声性能(工作频率可达 70 GHz)。Agilent PSG 模拟信号发生器的高输出功率和卓越的电…...

【C++】什么是函数模板/类模板?
文章目录 一、函数模板1.什么是函数模板?2.函数模板格式3.函数模板原理4.函数模板实例化(1)隐式实例化(2)显示实例化 二.类模板1.类模板定义格式2.类模板的实例化 总结 一、函数模板 1.什么是函数模板? 函…...

为什么是ChatGPT引发了AI浪潮?
目录 BERT和GPT简介 BERT和GPT核心差异 GPT的优势 GPT的劣势 总结 随着近期ChatGPT的火热,引发各行各业都开始讨论AI,以及AI可以如何应用到各个细分场景。为了不被时代“抛弃”,我也投入了相当的精力用于研究和探索。但在试验的过程中&…...

批处理文件(.bat)启动redis及任何软件(同理)
批处理文件 每次从文件根目录用配置文件格式来启动redis太麻烦了 可以在桌面上使用批处理文件(.bat)启动Redis,请按照以下步骤进行操作: 打开文本编辑器,如记事本。 在编辑器中输入以下内容: 将文件保存…...

深度学习求解稀疏最优控制问题的并行化算法
稀疏最优控制问题 问题改编自论文An FE-Inexact Heterogeneous ADMM for Elliptic Optimal Control Problems with L1-Control Cost { min y ( μ ) , u ( μ )...

牛客网项目—开发社区首页
视频连接:开发社区首页_哔哩哔哩_bilibili 代码地址:Community: msf begin 仿牛客论坛项目 (gitee.com) 本文是对仿牛客论坛项目的学习,学习本文之前需要了解Java开发的常用框架,例如SpringBoot、Mybatis等等。如果你也在学习牛…...

uniapp水文【uniapp】
文章目录 1、前言2、历史3、发展4、功能5、优缺点6、总结7、附录7.1、高频使用7.2、使用注意 1、前言 Uniapp是一种跨平台的移动应用开发框架,它允许开发者使用一套代码库,同时生成iOS、Android等多个平台的应用程序。这种技术方案可以大大降低开发成本…...

Java函数式接口
3 函数式接口 3.1 函数式接口概述 函数式接口:有且仅有一个抽象方法的接口 Java中的函数式编程体现就是Lambda表达式,所以函数式接口就是可以适用于Lambda使用的接口只有确保接口中有且仅有一个抽象方法, Java中的Lambda才能顺利地进行推导…...

安装libevent库
安装libevent库 yum install libevent libevent-devel 自动安装Memcached yum install memcached 源码安装 下载1.6.19版本 wget https://www.memcached.org/files/memcached-1.6.19.tar.gz (若证书过期yum install -y ca-certificates) 解压源码 tar -zxvf…...

vue 截取字符串的方法
vue中的字符串方法,我目前使用最多的是下面两种方法,因为 vue的字符串方法支持断言操作。 1、 vue中截取字符串的方法如下: 2、 vue中截取字符串的方法,这个方法也是需要依赖于 vue库提供的支持。 3、 vue中截取字符串的方法&…...

可数集和不可数集
有限集和无限集 后继集 设 S S S是任一集合,称 S S ∪ { S } S^ S\cup \left\{ S\right\} SS∪{S}为 S S S的后继集 自然数集 自然数集 N \mathbb{N} N的归纳定义是: (1) ∅ ∈ N \empty \in \mathbb{N} ∅∈N (…...

<Linux>《Linux 之 ps 命令详解大全(含实用命令)》
《Linux 之 ps 命令详解大全(含实用命令)》 1 常用命令1.1 显示所有当前进程1.2 显示所有当前进程1.3 显示所有当前进程1.4 根据用户过滤进程1.5 根据 CPU 使用来升序排序1.6 根据用户过滤进程1.7 查询全10个使用cpu和内存最高的应用1.8 通过进程名和PID…...

华为OD机试真题 Java 实现【寻找关键钥匙】【2023Q1 100分】
一、题目描述 小强正在参加《密室逃生》游戏,当前关卡要求找到符合给定 密码K(升序的不重复小写字母组成)的箱子,并给出箱子编号,箱子编号为1~N。 每个箱子中都有一个字符串s,字符串由大写字母,小写字母,数字,标点符号,空格组成,需要在这些字符串中找出所有的字母…...

项目中遇到的一些问题总结(十三)
extension-configs 和 shared-configs 的区别 在 Nacos 配置管理中,extension-configs 和 shared-configs 分别是两种不同类型的配置,它们的主要区别在于它们的使用场景和作用。 extension-configs 是一种应用程序向 Nacos 注册的扩展配置。它主要用于给…...

药品存销信息管理系统数据设计与实现(包括需求分析,数据库设计,数据表、视图、存储过程等)
前言 可前往链接直接下载: https://download.csdn.net/download/c1007857613/87776664 或者阅读本博文的详细介绍,本博文也包含所有详细内容。 一、需求分析 a.“药品存销信息管理系统”只是对数据库应用技术的一个样本数据库的实例,重在对数据库一些方法的熟悉与掌握,…...

PyTorch-Loss Function and BP
目录 1. Loss Function 1.1 L1Loss 1.2 MSELoss 1.3 CrossEntropyLoss 2. 交叉熵与神经网络模型的结合 2.1 反向传播 1. Loss Function 目的: a. 计算预测值与真实值之间的差距; b. 可通过此条件,进行反向传播。 1.1 L1Loss import torch from …...

centos docker安装mysql8
1、创建挂载文件夹 mkdir -p /mydata/mysql/log mkdir -p /mydata/mysql/data mkdir -p /mydata/mysql/conf 2、拉取镜像最新版本,如果写 mysql:8.0.26可以指定版本 docker pull mysql 3、启动命令 docker run -p 3306:3306 --restartalways -v /mydata/mysql/log:…...

Java中synchronized锁的深入理解
使用范围 synchronized使用上用于同步方法或者同步代码块在锁实现上是基于对象去实现使用中用于对static修饰的便是class类锁使用中用于对非static修饰的便是当前对象锁 synchronized的优化 在jdk1.6中对synchronized做了相关的优化 锁消除 在synchronized修饰的代码块中…...

Find My资讯|iOS17将重点改进钱包、Find My、SharePlay和AirPlay等功能
彭博社的马克・古尔曼(Mark Gurman)在最新一期 Power On 时事通讯中表示,苹果即将推出的 iOS 17 系统将改进 Wallet、Find My、SharePlay 和 AirPlay 等多项功能。 古尔曼在博文中还表示苹果会增强 Find My 的位置服务,同样也没…...

什么是webSocket?
什么是webSocket WebSockets是一种协议,它允许在Web应用程序中建立持久连接。这意味着当客户端与服务器建立连接后,它们可以始终保持连接状态,直到其中一个终止连接。相比于传统的HTTP协议,WebSockets提供了更高效的方式来处理实…...

黑马Redis视频教程高级篇(一:分布式缓存)
目录 分布式缓存 一、Redis持久化 1.1、RDB持久化 1.1.1、执行时机 1.1.2、RDB原理 1.1.3、小结 1.2、OF持久化 1.2.1、AOF原理 1.2.2、OF配置 1.2.3、AOF文件重写 1.3、RDB与AOF对比 二、Redis主从 2.1、搭建主从架构 2.1.1、集群结构 2.1.2、准备实例和配置 …...

SLMi331数明深力科带DESAT保护功能隔离驱动应用笔记
SLMi33X系列SLMi331数明深力科首款单通道带DESAT保护功能的IGBT/SiC隔离驱动器。内置快速去饱和(DESAT) 故障检测功能、米勒钳位功能、漏极开路故障反馈、软关断功能以及可选择的自恢复模式,兼容光耦隔离驱动器。 SLMi331的DESAT阈值为6.5V,其最大驱动电…...