搜索
查看
编辑修改
首页
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
web概述14_checkvalidity 获取异常
2
Spring中线程池ThreadPoolTaskExecutor的使用_threadpooltaskexecutor队列和唤醒
3
element-plus分页组件默认显示英文,设置成中文显示。_elementplus 组件是英文
4
CSS实现两行或多行文本超出用省略号...显示_css超过两行显示为...
5
超详细分析S3DIS数据集的构建
6
蓝桥杯刷题day08——完全日期
7
关于vue的elementUI和vue3的element-plus的el-dialog的样式以及el-table中的tooltip的样式修改(个人见解)_elementplus 弹出框修改样式
8
使用Batchmode、Jenkins打包UnityAPK_editorsetup.androidsdkroot
9
Nodejs入门实战一篇精通_nodejs开发
10
【Unity编辑器扩展】 | 编辑器扩展 特性(Attribute) 整理总结 | 建议收藏_unity 编辑器attr
当前位置:
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
Netty
心跳
检测机制_
super
.
usereventtriggered
...
心跳
检测机制目的:就是用于检测 检测通信对方是否还"在线",如果已经断开,就要释放资源 或者 尝试重连。大概的实现原理就...
赞
踩
article
TCP
/IP
网络
编程
Client
客户端详解_
tcp
/ip
client
...
TCP
/IP
网络
编程
Client
客户端详解懒得搬运,请进入我的网站www.liujianhua.xyz阅读~~_
tcp
/...
赞
踩
article
Spring
Boot
中
数据库
操作是怎么实现的_
springboot
不建
servie
层和
mapper
...
上篇文章中已经通过一个简单的HelloWorld程序讲解了
Spring
boot的基本原理和使用。本文主要讲解如何通...
赞
踩
article
毕业设计
基于
微信
的
在线听
歌听书
小
程序
uniapp_
基于
微信
小
程序
开发有声书...
随着时代的发展我国的移动互联网也逐渐的完善,很是时候人们希望通过移动设备听歌和听一些
小
说文学作品等内容,但是一些市面上的...
赞
踩
article
Layui
后端
返回
的
json
数据格式
和前端
table
要求
的
不一致-----Day2_后端
返回
的
数据...
Layui
后端
返回
的
json
数据格式
和前端
table
要求
的
不一致layui要求格式为但是后端传过来
的
格式是这样
的
解决办...
赞
踩
article
微软
面试准备_五个
人
的
商业价值
...
面试准备1、岗位2、Azure3、云计算1、公有云、私有云和混合云2、云服务Iass、Pass和Pass1、岗位Clou...
赞
踩
article
Python
语法
及
入门
(
超全超
详细) 专为
Python
零
基础
一篇
博客
让你完全掌握
Python
语...
Python
语法
及
入门
(
超全超
详细) 专为
Python
零
基础
一篇
博客
让你完全掌握
Python
语法
_python语...
赞
踩
article
后台返回
JSON
数据格式
不符合
layui
.
table
要求的
数据格式
_一种后台返回
数据格式
字段不一致的...
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插...
赞
踩
article
幻兽
帕鲁
服务器
搭建
,
无需公网IP和
服务器
...
幻兽
帕鲁
一款支持多人游戏模式的全新开放世界生存制作游戏
,
核心玩法包括怪物养成、战斗、领域探索、建造、制作等。目前抢先体验...
赞
踩
article
mybatis
循环超过
1000
条报错的处理办法_
mybatis
的
where
条件
用
or
拼接
大于
1000
...
112让3人_
mybatis
的
where
条件
用
or
拼接
大于
1000
个
mybatis
的
where
条件
用
or
拼接
大于
1000
...
赞
踩
article
【办公类-2
1
-04】20240227单个
word
按“
段落
数”
拆
分多个
Word
(
三级
育婴师
操作
参考
题...
【办公类-2
1
-04】20240227单个
word
按“
段落
数”
拆
分多个
Word
(
三级
育婴师
操作
参考
题目 有
段落
文字和表格...
赞
踩
article
UNIX
网络编程-
TCP
相关_
当
进程
调用
accept
时...
TCP
客户端和服务端_
当
进程
调用
accept
时
当
进程
调用
accept
时 目录 相关函数 套接...
赞
踩
article
centos
7
安装
podman
(类似
docker
)_
centos
7
podman
...
Podman 是一个无守护、开源的 Linux 本地工具,旨在使用 open Containers Initiative...
赞
踩
article
如何
编写
可
测试
的
代码
:
两个
核心三个思路...
????导读在需要长期迭代
的
项目中
编写
单元
测试
,已经在各个团队中逐渐成为一种虚伪
的
共识。虽然嘴上都说好,但身体很诚实。?...
赞
踩
article
BSV
上用于通用
计算
的
隐私非
交互式
赏金
_
bsvw
...
我们提出了一种新颖
的
赏金
机制,可以在区块链上安全私密地外包任意
计算
。解决方案和付款
的
交换是原子
的
和无需信任
的
:
赏金
发布者...
赞
踩
article
linux
系统
安装
telnet
服务端_
linux
安装
telnet
...
linux
系统
安装
telnet
服务端_
linux
安装
telnet
linux
安装
telnet
一、...
赞
踩
article
web
项目开发 之
前端
规范
---
JSON
数据
传输
规范
_
前端
数据
规范
...
web
项目开发 之
前端
规范
---
JSON
数据
传输
规范
_
前端
数据
规范
前端
数据
规范
...
赞
踩
article
如何做
代
币
分析
:以
TRX
币
为例...
通过
代
币
分析
,我们可以获得对市场趋势、风险因素、交易活动和资金流向的投资决策。如何做
代
币
分析
:以
TRX
币
为例 ...
赞
踩
article
【
Java
后台
开发
规范
】---
设计
原则_后端
接口
设计
规范
...
文章目录前言其他类型的
规范
设计
原则单一职责开闭原则里式替换原则
接口
隔离原则依赖倒置原则迪米特法则DRY原则KISS原则总...
赞
踩
article
使用
DataX
进行
数据
同步
_
datax
同步
数据
时源表
结构
变化
而
变化
...
DataX
是一个异构
数据
源离线
同步
工具,可以实现
数据
源之间的
数据
同步
。 ODPSWriter插件适合于TB,GB数量级...
赞
踩
相关标签
java
linux
http
c语言
网络
开发语言
后端
课程设计
微信
小程序
面试
python
学习方法
程序人生
html
服务器
tcp/ip
运维
linq
c#
wpf
centos
podman
容器