搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
Gausst松鼠会
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
dell服务器增加磁盘阵列,Dell PowerEdge服务器如何通过联机容量扩充的方式实现磁盘阵列扩容?...
2
服务器主体 无法在当前安全上下文下访问数据库
3
可持久化线段树练习(一)_可持久化线段树题单
4
使用快解析搭建自己的minecraft服务器_域名智能解析 mc服务器
5
基于Python爬虫黑龙江哈尔滨酒店数据可视化系统设计与实现(Django框架) 研究背景与意义、国内外研究现状
6
python绘图输出上下标中的上下标_python输出带有上下标
7
【shell脚本】监控磁盘/内存使用率·检测域名是否正常·一键部署LMNP·拉黑攻击服务器的异常ip
8
Web前端之Flask框架--flask简介、Jinja2模板引擎_前端flask框架
9
STM32 HAL库函数——HAL_UART_RxCpltCallback()详解
10
linux yum 命令_linux yum clean
当前位置:
article
> 正文
计算机网络协议第九章,TCP连接的建立与终止_并以 a 计算机为主动提出连接终止的一端,绘图说明 tcp 终止连接时各步骤的信
作者:Gausst松鼠会 | 2024-02-28 12:26:08
赞
踩
并以 a 计算机为主动提出连接终止的一端,绘图说明 tcp 终止连接时各步骤的信
TCP协议作为有状态的服务,本章围绕这一主题进行详细讲解。本章主要分解连接建立和终止两个部分阐述TCP的状态,并且对TCP连接建立和终止的一些常见问题进行分析。
TCP的状态机
下面我们看一下TCP状态机的图例:
一共分为两个部分,第一部分是关于连接建立的5个状态,第二部分是关于连接终止的7个状态。
连接建立状态是ESTABLISHED状态及其以上半部分,连接终止则是其下半部分。
首先初始状态为CLOSED状态,通过三步握手成功后转换为ESTABLISHED状态。最好通过4步链接终止最终再次转换到CLOSED状态,这就是网络连接状态机的闭环。
下面通过连接的建立和拆除分解的方式来理解TCP状态机。
网络连接的建立
左侧一方为连接的主动方,通常是一个client角色,右侧则是连接的接受方,通常是一个server 角色。
步骤一、主动方通过connect 调用会发送一个SYN的TCP分节,此时socket 状态从CLOSED状态转换为SYN_SENT状态。
步骤二、接受方通过listen监听到SYN分节后,此时socket状态从CLOSED状态转换为SYN_RECV状态。并且发送SYN,ACK分节。
步骤三、主动方收到接受方的SYN,ACK分节后socket状态转换为ESTABLISHED, 并且发送ACK分节。
步骤四、接受方收到ACK分节后socket状态切换为ESTABLISHED状态。
连接双方都是经过一发一收两个步骤,最终都进入ESTABLISHED状态。看起来这个TCP连接建立也非常简单,但是里面也蕴含很多设计的思想。
在发送SYN分节时,需要初始化seq(Sequence Number简写)的值,如果细心的同学通过wireshark等抓包工具查看的时候发现seq=0,但是实际上seq是不为0的,因为抓包工具为了方便使用者分析而采用了相对seq。一般内核协议栈会根据时间的因子做一个随机的seq值,保证每次连接时尽可能不同。
接受方发送了SYN,ACK分节中的seq也是需要初始化一个值,是一个道理,而ACK Number则是需要在上一个SYN分节的seq上加1。
发送方收到SYN,ACK分节后,ACK Number也是需要加1,道理是同样的,因为当TCP的Data为0时也需要加1处理,如果TCP的Data有10个字节,ACK Number可以表示有多少字节被收到,ACK Number和Seq Number是相辅相成的,ACK Number可以告知发送方多少数据被接收,它被用于重传机制。Seq Number的保证每次发送时的序号不同,这样就能够保证发送报文的顺序。
下面看下连接建立后,发送1个字节的数据的相互流程,就比较容易理解Seq Number和Ack Number了
网络连接的终止
左侧我们称为连接主动关闭方,右侧为被动关闭方。通过close调用就可以发送FIN分节。
步骤一、主动方发送FIN分节后,socket状态从ESTABLISHED状态转换位FIN_WAIT_1。
步骤二、被动方收到FIN分节后,进入到CLOSE_WAIT状态并且发送ACK分节确认。
步骤三、被动方调用close函数,发送FIN分节,socket转换切换为LAST_ACK状态
步骤四、主动方收到步骤二发来的ACK分节后进入FIN_WAIT_2状态。
步骤五、主动方收到步骤三发来的FIN分节后进入TIME_WAIT状态,并且回复ACK分节。
步骤六、被动方收到ACK分节后,socket状态重新回到CLOSED状态。
连接的关闭流程确实比建立复杂一些,可以看到被动关闭方最终进入到CLOSED状态,而主动关闭方却进入到TIME_WAIT状态。主要看第一张图,当TIME_WAIT状态经过2个MSL周期后后最终进入到CLOSED状态,因此形成状态机的闭环。
TCP连接建立和终止扩展
连接同时打开
在第一张图的如下图所示部分就是同时打开的情况。
当主动方发生SYN分节后进入到SYN-SENT状态后,正常而言应该是等待SYN,ACK分节,但是等到的是SYN分节,这就以为则连接的对方同时发生SYN分节,这就叫同时打开,此时应该回复ACK分节并且进入到SYN-RECEIVED状态,等待ACK分节,而对方的情况也是如此,因此都会进入到SYN-RECEIVED状态等待ACK,如此就会出现连接过程中四个分节,2个SYN和2个ACK,当每方都收到对方的ACK分节后同时进入到ESTABLISHED状态。
这里讲一个关于同时打开的小话题,如果用TCP链接本机的某一个服务端口的时候,某些情况下会出现“鬼打墙”的现象,就是自己发送的数据又被自己给收到了,出现这个问题的原因就是因为出现自连接,而自连接就是一直同时打开的现象,其实很好复现这个问题,字节建立一个连接,然后又使用同一个fd连接自己监听的端口。 当然有时不是故意为之也会出现,比如你像连接本机的1234端口,而这个12345端口的服务没有起来,而正好系统把它分给给你创建的fd,当你去连接这个端口的时候就变成自连接了。
连接同时关闭
上节没有将CLOSING这个状态,这个状态只会出现在同时关闭的时候,不少很常见,当一方发送FIN分节进入到FIN_WAIT_1状态是,正常情况下应该等等ACK分节,可是等待的却是FIN分节,这就意味着同时关闭,然此时应该进入到CLOSING状态并且等带对方的ACK,如果收到ACK则进入到TIME_WAIT状态。
SYN超时和SYN FLOOD攻击
SYN超时是如此,当发送SYN一段时间没有回应时,会不间断的发送SYN包以防止丢包,而发送时间间隔会不停的地址,一般直观感受是connect等待30秒(根据内核而定)左右后会提示连接超时。也就是TCP内核会尝试多次,如果依然没有回应才会超时。
SYN FLOOD 攻击是一个比较常见的DOS攻击手段,它的手段是发送SYN分节报文后,不在响应SYN,ACK分节,让对方一直无法完成连接的建立,linux内核有一个队列保持这种连接,并且队列有一定大小,通过内核参数tcp_syncookies而定,如果内核的队列被这种SYN报文多次攻击后,会占满内核的队列导致正常的连接无法等到响应。形成DOS攻击。
解决这个方法有三个参数可以调配,
第一个是:
tcp_synack_retries
可以用他来减少重试次数;第二个是:
tcp_max_syn_backlog
,可以增大
SYN
连接数;第三个是:
tcp_abort_on_overflow
处理不过来干脆就直接拒绝连接了。一般大公司会有专门保持TCP连接的机器,他们修改内核并有自己保护的策略,能够扛住百万级甚至更高的SYN FLOOD攻击。
FIN_WAIT_1状态和半关闭
写个HTTP服务的同学可能会遇到HTTP的QPS效率出现异常而CPU和内存还有很多空间的情况,然后才发现原来80端口有很多socket处于FIN_WAIT_1状态,出现这个状态是因为HTTP服务端关闭了连接,但是客户端没有调用close,发送FIN分节,导致服务socket长期处于FIN_WAIT_1状态导致fd句柄占用,从而导致服务响应性能下降。这个现象就称为半关闭状态。
那网络内核就一直不清理FIN_WAIT_1状态吗,也不是, 而是要等很长一段时间才能清理,可以将TCP的心跳包活时常设置短一些,这样能够加快对FIN_WAIT_1状态的回收。
TIME_WAIT状态和MSL
先解释MSL,MSL的意思为最大传输周期,也就是IP报文在网络中存活的最大时常,它在Linux中被设置为30秒,可以认为MSL=30秒。
什么是TIME_WAIT状态,这个状态的目的是什么? TIME_WAIT状态是主动断开连接方最终进入的状态,为什么要进入到TIME_WAIT状态呢,因为TCP设计者认为如果没有这个状态,一个连接断开后,这个端口如果再次被使用并且向上一次连接目的地址发送报文,那么可能上一个连接发送的报文在网络上延时后再次到达目的地址,这样目的地址会同时收到上一次连接和这一次连接的数据,有可能无法区分而带来问题。因此TCP设计者认为如果进入到TIME_WAIT后,必须等到2*MSL时间端口才能被复用,这样才会比较安全。
还记得初始化Seq Number吧,上面提到要使用一个随机值来初始化Seq Number,它也是一种防止这种现象的设计,当然也不一定完全有效,但是大多数时候是有用的。
HTTP服务是短连接的情况,如果Server端主动端开连接就会产生TIME_WAIT状态,然后TIME_WAIT状态也是占用系统资源的,这也是为什么大牛设计系统时都是让客户端主动端口连接的原因了,当然也不是所有场景都能让客户端先端开连接的,系统提供
tcp_max_tw_buckets参数来控制TIME_WAIT的最大数量。
当客户端的场景下,如果重启进程后会出现上一个连接TIME_WAIT状态,当时有想复用这个端口,那么socket提供SO_REUSE_ADDRESS参数来复用TIME_WAIT状态的端口。
close于shutdown调用
在编写TCP协议会碰到这样一个问题,就是发送完数据后关闭连接,对方并没有将数据全部收全,原因在于调用close函数,以为你当自己的接受缓存中有数据可读时,但是没有全部读到应用层而直接调用close函数,会发送RST分节,如果发送RST分节,这样写缓冲的数据将会被丢弃,因此对方是无法收全你发送的数据的,正确的做法是调用shutdown函数,然后使用recv函数将接受缓冲队列的数据收全,当对方收到FIN分节后,也好发送ACK分节和FIN分节,如此shutdown调用方式也好收到recv == 0的时间,这时再调用close方法关闭fd。
小结
本章主要讲解TCP的状态机,并且通过讲解TCP连接建立和终止的坑来加深对TCP协议的理解,掌握如何避免掉进这些坑中。TCP的因为有状态的服务会带来一定性能问题,在媒体传输中不是被首选使用,后续有机会再讲下SCTP和T/TCP这两种协议。
参考
《TCP/IP详解-协议》卷一
W.Richard Stevens
修订
初稿 2015-3-27 Simon
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/158788
推荐阅读
article
滴滴
(夜莺)
Nightingale
监控
部署_
go
的
nighingale
...
Nightingale
是一套衍生自Open-Falcon
的
互联网
监控
解决方案,融入了
滴滴
的
最佳实践,由于改动太大,优化太...
赞
踩
article
python
爬虫编码问题
_
python
爬取
网页
数据
将
文本
转码...
对于
爬取
到的
网页
数据
中文乱码的解决方案
_
python
爬取
网页
数据
将
文本
转码
python
爬取
网页
数据
将
文本
转码 ...
赞
踩
article
使用
Docker
搭建
YesPlayMusic
并实现公网访问本地云
音乐
播放器
_
音乐
docker
搭建
...
使用
Docker
搭建
YesPlayMusic
并实现公网访问本地云
音乐
播放器
_
音乐
docker
搭建
音乐
docker
搭建
...
赞
踩
article
速学!4种
Python
处理
Excel
数据
的方法!_
python
excel
...
xlwt模块只能写xls文件,不能写xlsx文件(写xlsx程序不会报错,但最后文件无法直接打开,会报错)。openpy...
赞
踩
article
Linux
ssh
密钥
创建及
密钥
登录_
ssh
pub
.
id
...
创建
密钥
1.在命令行输入
ssh
-keygen -t rsa生成
密钥
2.在询问框中一路回车,会在/root/.
ssh
/文件...
赞
踩
article
Podman
使用
详解...
防火墙的作用不会影响网络的设置和配置,但会影响这些网络上的流量。UID / GID 1是第一个UID / GID在用户在...
赞
踩
article
解决连接
数据库
Access
denied
for
user
‘
root
‘@‘
localho
st‘ (...
我的项目是springboot项目,其它项目也可以参考。启动项目时,报错信息显示:HikariPool-1 - Exce...
赞
踩
article
TCP协议重点
注意事项
_
tcp
/
server
给
tcp
/
client
返回数据时
需要
指定ip地址码...
1.
tcp
服务器一般情况下都
需要
绑定端口和IP地址,否则客户端找不到这个服务器2.
tcp
客户端一般不绑定,因为是主动...
赞
踩
article
帕鲁
存档
跨云迁服教程_帕努
服务器
存档
迁移
...
包含 10GB 的轻量对象存储容量和 1 GB的公网下行流量,非常适合想要尝鲜的用户。2. 进入上一阶段创建的存储桶,下...
赞
踩
article
TCP
连接的状态与关闭方式,及其对
Server
与
Client
的影响_dms
tcp
server
l...
首先介绍一下
TCP
连接建立与关闭过程中的状态。
TCP
连接过程是状态的转换,促使状态发生转换的因素包括用户调用、特定数据包...
赞
踩
article
设置
TCP
的
keepalive
来进行
网络
联调_settcp
keepalive
...
转载:设置
TCP
的
keepalive
来进行
网络
联调_北雨南萍
的
博客-CSDN博客使用
TCP
的
keepalive
来检查
网络
...
赞
踩
article
UE
4
入门学习
4
:
C++
编程介绍
_
ue
4
测量面积
c++
...
UE
4
直接使用
C++
作为逻辑层语言,这样引擎层与逻辑层语言统一,不需要胶水代码去转发,消除了逻辑层和引擎层的交互成本。为...
赞
踩
article
保存
markdown
格式
复制
网页
_如何
复制
网页
/
markdown
...
sdn保存
markdown
格式
复制
网页
_如何
复制
网页
/
markdown
如何
复制
网页
/
markdown
...
赞
踩
article
想要远程
服务器
长时间
挂机
不断开
ssh
连接
的
技巧...
使用top命令挂着就好了,top命令执行
的
“查看系统进程和资源占用”
的
任务会一直输出动态
的
数据,一直有数据传输就不会因为...
赞
踩
article
JNI DETECTED ERROR IN APPLICATION: can'
t
call
void
...
//cmake使用JNIEXPORT
void
JNICALLJava_com_
example
_wxy_ndks_U
t
i...
赞
踩
article
ssh
登录时常出现的几种错误以及
解决
方法
(
Linux
)_
ssh
command
error
.[us...
前言
ssh
是
Linux
系统中常用的远程登陆的命令,有的时候我们通过xshell等远程连接软件使用
ssh
去登陆远程的服务器...
赞
踩
article
轻松与
朋友
组队!
幻兽
帕鲁
Palworld
联机
服务器
搭建...
当
服务器
状态变为“运行中”后,您和您的
朋友
就可以通过
服务器
的公网IP地址:8211,进入
幻兽
帕鲁
的世界尽情玩耍了。此外,...
赞
踩
article
pandoc
word
转
markdown
之后
正则
修改_
pandoc
图片
居中...
但是我要展示到前端的,前端组件用的v-md-preview,结果展示的时候,后面的宽高没有识别,也展示出来了,那么就得把...
赞
踩
article
使用
Java
(
SpringBoot
)搭建
DPlayer
视频
弹幕
接口
API
...
弹幕
功能java开发_
弹幕
接口
api
弹幕
接口
api 前言  ...
赞
踩
article
mybatis
基础:
sqlsession
、
连接
配置
、
db
配置
加载顺序等_
db
sqlsession
...
mybatis
的Sqlsession
、
配置
加载顺序
、
基本 CRUD使用
、
高级查询方式
、
事务
、
java bean别名等_d...
赞
踩
相关标签
linux
服务器
监控类
falcon
网络爬虫
python
docker
eureka
容器
内网穿透
excel
开发语言
学习方法
职场和发展
RSA
java
数据库
腾讯云
轻量COS
网络
ue4
notepad++
编辑器