为什么TCP 建连接要3次,断连接却要4次呢?
大家好,今天聊聊传输层通信协议TCP的经典问题:建连接与断连接。
网络上的传输是没有连接的,包括TCP也是一样的。
而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。
很多人会问,为什么建链接要3次握手,断链接需要4次挥手?
-
对于建链接的3次握手,主要是要初始化Sequence Number 的初始值。通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序(TCP会用这个序号来拼接数据)。
-
对于4次挥手,其实你仔细看是2次,因为TCP是全双工的,所以,发送方和接收方都需要Fin和Ack。只不过,有一方是被动的,所以看上去就成了所谓的4次挥手。如果两边同时断连接,那就会就进入到CLOSING状态,然后到达TIME_WAIT状态。下图是双方同时断连接的示意图(你同样可以对照着TCP状态机看):
另外,有几个事情需要注意一下:
-
关于建连接时SYN超时。试想一下,如果server端接到了clien发的SYN后回了SYN-ACK后client掉线了,server端没有收到client回来的ACK,那么,这个连接处于一个中间状态,即没成功,也没失败。于是,server端如果在一定时间内没有收到的TCP会重发SYN-ACK。在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 2^6 -1 = 63s,TCP才会把断开这个连接。
-
关于SYN Flood攻击。一些恶意的人就为此制造了SYN Flood攻击——给服务器发了一个SYN后,就下线了,于是服务器需要默认等63s才会断开连接,这样,攻击者就可以把服务器的syn连接的队列耗尽,让正常的连接请求不能处理。于是,Linux下给了一个叫tcp_syncookies的参数来应对这个事——当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie发回来,然后服务端可以通过cookie建连接(即使你不在SYN队列中)。请注意,请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为,synccookies是妥协版的TCP协议,并不严谨。对于正常的请求,你应该调整三个TCP参数可供你选择,第一个是:tcp_synack_retries 可以用他来减少重试次数;第二个是:tcp_max_syn_backlog,可以增大SYN连接数;第三个是:tcp_abort_on_overflow 处理不过来干脆就直接拒绝连接了。
-
关于ISN的初始化。ISN是不能hard code的,不然会出问题的——比如:如果连接建好后始终用1来做ISN,如果client发了30个segment过去,但是网络断了,于是 client重连,又用了1做ISN,但是之前连接的那些包到了,于是就被当成了新连接的包,此时,client的Sequence Number 可能是3,而Server端认为client端的这个号是30了。全乱了。RFC793中说,ISN会和一个假的时钟绑在一起,这个时钟会在每4微秒对ISN做加一操作,直到超过2^32,又从0开始。这样,一个ISN的周期大约是4.55个小时。因为,我们假设我们的TCP Segment在网络上的存活时间不会超过Maximum Segment Lifetime(缩写为MSL – Wikipedia语条),所以,只要MSL的值小于4.55小时,那么,我们就不会重用到ISN。
-
关于 MSL 和 TIME_WAIT。通过上面的ISN的描述,相信你也知道MSL是怎么来的了。我们注意到,在TCP的状态图中,从TIME_WAIT状态到CLOSED状态,有一个超时设置,这个超时设置是 2*MSL(RFC793定义了MSL为2分钟,Linux设置成了30s)为什么要这有TIME_WAIT?为什么不直接给转成CLOSED状态呢?主要有两个原因:1)TIME_WAIT确保有足够的时间让对端收到了ACK,如果被动关闭的那方没有收到Ack,就会触发被动端重发Fin,一来一去正好2个MSL,2)有足够的时间让这个连接不会跟后面的连接混在一起(你要知道,有些自做主张的路由器会缓存IP数据包,如果连接被重用了,那么这些延迟收到的包就有可能会跟新连接混在一起)。
-
关于TIME_WAIT数量太多。从上面的描述我们可以知道,TIME_WAIT是个很重要的状态,但是如果在大并发的短链接下,TIME_WAIT 就会太多,这也会消耗很多系统资源。只要搜一下,你就会发现,十有八九的处理方式都是教你设置两个参数,一个叫tcp_tw_reuse,另一个叫tcp_tw_recycle的参数,这两个参数默认值都是被关闭的,后者recyle比前者resue更为激进,resue要温柔一些。另外,如果使用tcp_tw_reuse,必需设置tcp_timestamps=1,否则无效。这里,你一定要注意,打开这两个参数会有比较大的坑——可能会让TCP连接出一些诡异的问题(因为如上述一样,如果不等待超时重用连接的话,新的连接可能会建不上。正如官方文档上说的一样“It should not be changed without advice/request of technical experts”)。
·················· END ··················
关注公众号,免费领取程序员成长大礼包
十年研发路,大厂架构师,CSDN博客专家
专注架构技术学习及分享,职业与认知升级
坚持分享接地气儿的干货,期待与你一起成长
推荐阅读
「架构精进之路」专注架构研究,技术分享
点“赞”和“在看”哦
本文分享自微信公众号 - 架构精进之路(jiagou_jingjin)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
数栈技术分享:到底什么是数据中台?终于有人说清楚了!
一、关于袋鼠云和数据中台 2017年杭州云栖大会上,袋鼠云正式将「数据中台」作为自己的业务战略方向。 2018年,袋鼠云在业内率先推出《袋鼠云数据中台专栏V1.0》,阐述自己的数据中台理念和方法论。 2019年,袋鼠云基于两年来在数据中台领域的探索和实践经验,推出《袋鼠云数据中台专栏V2.0》升级版。 二、 数据中台是理念,是方法论 【数据中台】理念由阿里云和袋鼠云最先提出。 袋鼠云依托最新的数据采集、加工处理、数据挖掘、机器学习,深度学习等技术,并结合自身多年数据应用经验,打造了袋鼠云数据中台解决方案,致力于构建“全”、“统”、“通”的大数据体系,基于「互联网+」时代的数据价值思考,构建全域数据共享能力中心,助力企业数字化,提升企业竞争力! 数据中台的实质是为企业构建「全域数据的共享能力中心」,提供数据采集、数据建模、数据研发、数据萃取、数据治理、数据服务等全链路一站式服务,构建面向业务应用的数据智能平台。 很多人会认为,【数据中台】只是一个炒出来的词汇,听起来和传统的数据仓库没有什么不同啊。 针对这个问题,我们总结了「数据中台」和「数据仓库」的几个明显的优越性: 分布式数据平台 传...
- 下一篇
这个好用的分布式应用配置中心,我们把它开源了
导读:SpringBoot的时代到来,对于曾经面向一堆XML配置的开发经历,那真是一大福音,一切都变得非常简洁,留下的就是简化的配置文件设置。但在分布式环境下呢?众多的实例集群下,动态的实例迁移等情况时常发生,导致配置管理的工作变得复杂且困难,百度研发团队通过多年的架构建设经验,把过往的配置管理的相关经验沉淀成一套通用的解决方案,现以开源的方式回馈给社区开发者,希望帮助大家彻底解决配置建设的难题。 全文约4200字,预计阅读时间8分钟。 1 分布式环境下的配置管理挑战 可以说配置化是当今应用开发与部署必备的一个能力要求,我们通常把一些容易变化以及依赖外部情况而变化的内容,通过配置化的方式来实现,这样我们就可以在零编码的情况下实现功能调整,实现极低成本的应用扩展能力。而对于配置管理方式,最为常见的方式就是配置文件方式, 通过特定的文件内容格式进行设置, 部署时也会与应用程序放在一起。这样使用方式在单机情况下比较容易且简单,但是在大型的分布式应用场景下,特别又要区分不同环境(开发,测试,线上等)就会导致管理成本与出错风险急速加大。 以上述场景为例,涉及的问题与挑战有: 操作复杂,成本高:如...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作