TCP中的状态转移(三种情况)

news/2024/10/30 15:27:22/

文章目录

  • 前言
  • 一、 TCP的生命周期
  • 二、另外两种挥手情况
  • 三、经典四问
  • 总结


前言

博主个人社区:开发与算法学习社区

博主个人主页:Killing Vibe的博客

欢迎大家加入,一起交流学习~~

在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接,但断开连接的时候,由于双方的关闭时机不同,双方也相应的会有不同的状态。

一、 TCP的生命周期

这里有张图很好的总结了TCP整个生命周期(情况一):

在这里插入图片描述
服务端状态转化:

  • [CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态,等待客户端连接;
  • [LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段),就将该连接放入内核等待队列中,并向客户端发送SYN确认报文。
  • [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文,就进入ESTABLISHED状态,可以进行读写数据了。
  • [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调用close),服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据);当服务器真正调用close关闭连接时,会向客户端发送FIN,此时服务器进入LAST_ACK状态,等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
  • [LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK,彻底关闭连接。

客户端状态转化:

  • [CLOSED -> SYN_SENT] 客户端调用connect,发送同步报文段;
  • [SYN_SENT -> ESTABLISHED] connect调用成功,则进入ESTABLISHED状态,开始读写数据;
  • [ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时,向服务器发送结束报文段,同时进入FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认,则进入FIN_WAIT_2,开始等待服务器的结束报文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段,进入TIME_WAIT,并发出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life,报文最大生存时间)的时间,才会进入CLOSED状态。

二、另外两种挥手情况

当然上面的图只是其中一种情况,对应了博主之前讲4次挥手的情况一(总共有三种情况)。

下面博主给大家带来另外两种变形的情况:(是不是究极折磨🤔)

分别是情况二情况 三 :(先记住)
在这里插入图片描述
解析:

  1. 对于情况二,是客户端想关闭了,发送了个FIN到服务器。服务器收到FIN的同时刚好想关闭,收到了FIN之后,把自己的FIN 主动发送了出去(顺带了个ACK),此时就没有CLOSE_WAIT状态了,因为服务器也是主动关闭的,客户端也没有了FIN_WAIT 2状态。(相比较于情况一)
  2. 对于情况三,是服务器在收到客户端发送的FIN 之前,也想主动关闭,把自己的FIN 主动发送了出去。当处于FIN_WAIT 1状态的端 收到了对方传来的FIN,并且要回一个ACK的时候,就会进入CLOSING状态。

好,有了上述三种情况,就可以理解下面的TCP状态汇总图了(不理解也无所谓,记住挥手阶段有三种情况就行):

在这里插入图片描述

首先,大家握手的状态变化都是一样的,区别就在挥手阶段:

分了三种情况(这里说服务器和客户端是为了好理解):

情况一:四次挥手,服务器是被动关闭的一方,客户端主动关闭;
情况二:三次挥手,服务器和客户端都是主动关闭的一方;
情况三:四次挥手,服务器和客户端都是主动关闭的一方。

在这里插入图片描述

注意:(看了下面我说的,应该有助于理解)

CLOSE_WAIT 状态

留心观察一下三种情况,是不是发现这个状态只发生在情况一里面,也就是只发生在被动方身上,出现在只有一方提出了挥手(FIN)。

TIME_WAIT状态:

留心观察一下,这个状态三种情况都有,但是只发生在主动方身上,出现在基本挥手已经结束的情况。

三、经典四问

好了,到这里,相信读者们对这个状态转化有了初步了解,现在博主有四个问题,帮助大家更好理解这些状态:

问题一:

服务器上出现大量CLOSE_WAIT状态的TCP连接,请问这种现象是否合理?

答:

不确定。单纯这个现象无法明确断言是否正常的。

因为,如果我们的程序设计时,会出现比较长时间的单方面关闭的情况时,出现大量的CLOSE_WAIT是合理现象。

但如果我们没有这种设计,则不合理,可能的原因是我们这一侧忘记调用socket.close()

问题二:

服务器上发现了大量的TIME_WAIT的TCP连接,是否合理?

答:

理论上讲合理,就是代码正常的关闭了连接,只是主动关闭的TCP连接比较多罢了。

但是实践上来说是不合理的。因为维护连接是有成本的(最主要的硬件成本就是内存)。

客户端上背负的连接比较少(几百条),服务器上背负的连接很多(几十万-几百万)。所以,如果让服务器背负这个TIME_WAIT连接的成本,相对压力较大,所以一般建议让客户端来背这个成本。

所以一般做网络编程设计时,不建议服务器去主动关闭连接(某些特殊情况下该主动关闭还是得主动的)

问题三:

既然挥手的工作已经完成了,为什么要有个TIME_WAIT状态而不是直接进入CLOSED状态?

答:

在这里插入图片描述

1. 我们不能保证最后一个ACK 接收方一定能收到,如果接收方没收到就不能closed,就会重发FIN,如果发送方没有这个TIME_WAIT状态,收到FIN就不能ACK了,那接收方就关闭不了了。

2.TCP靠五元组来区分连接,五元组就是一条连接的主键信息,连接如果没有经过TIME_WAIT释放,则五元组就会立即又被分配出去了。如果此时收到了一些之前网络传输比较慢的一些数据,就不能判断是谁发过来的了,有可能是上一个进程发送的。

问题四:

为什么是TIME_WAIT的时间是2MSL?

  • MSL是TCP报文的最大生存时间,因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启,可能会收到来自上一个进程的迟到的数据,但是这种数据很可能是错误的);
  • 同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失,那么服务器会再重发一个FIN。这时虽然客户端的进程不在了,但是TCP连接还在,仍然可以重发LAST_ACK);

MSL是个理论值,实际中很多OS取的是经验值,一般取一分钟。所以默认情况下TIME_WAIT的持续时间是2分钟。这个值可以修改。

总结

以上就是TCP状态转移的三种情况,觉得有帮助的朋友可以点赞收藏一波,有什么疑问可以私信博主。


http://www.ppmy.cn/news/10296.html

相关文章

第一章 Flink简介

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 前言 流计算产品实时性有两个非常重要的实时性设计因素,一个是待计算…

uni微信小程序,打开地图,跳转第三方

一、需求 微信小程序 需要点击并跳转第三方地图软件导航,并计算到目标位置距离 二、思路 思路: 1.接口返回需要有位置的经纬度,这个自行在后台编辑获取 2.需要获取用户的位置权限 我这边使用的是uniapp,需要使用官方封装两个…

【python 基础篇 五】python的常用数据类型操作-------列表

目录1.列表的基本概念和定义2.列表的常用操作2.1 列表的增加操作2.2 列表的删除操作2.3 列表的修改操作2.4 列表的查找操作2.5 列表的遍历操作2.6 列表的判断和比较操作2.7 列表的排序操作2.8 列表的乱序和反转操作1.列表的基本概念和定义 概念:有序的可变的元素集…

c++11 标准模板(STL)(std::forward_list)(一)

定义于头文件 <forward_list> template< class T, class Allocator std::allocator<T> > class forward_list;(1)(C11 起)namespace pmr { template <class T> using forward_list std::forward_list<T, std::pmr::polymorphic_…

指针进阶篇(1)

目录 &#x1f914; 前言&#x1f914; 一、&#x1f60a;字符指针&#x1f60a; 二、&#x1f61c;指针数组&#x1f61c; 三、&#x1f61d;数组指针&#x1f61d; 3.1数组指针的定义 3.2&数组名VS数组名 3.3数组指针的使用 四、&#x1f31d;数组参数&#xff0c…

基础算法(二)——归并排序

归并排序 介绍 归并排序是一种复杂度O(nlog(n)nlog(n)nlog(n))的排序算法&#xff0c;并且在任何情况下都是&#xff0c;但是它不是原地算法&#xff0c;即需要额外存储空间 其原理是&#xff0c;先将区间均匀分成左右两半&#xff0c;然后再对左右两半继续二分&#xff0c;…

LeetCode 138. 复制带随机指针的链表(C++)

思路&#xff1a; 用哈希表实现&#xff0c;创建一个哈希表来对应原链表中的每一个节点&#xff0c;这样也可以将原链表中的所有结点的next和random关系映射到哈希表复制链表中。 原题链接&#xff1a;https://leetcode.cn/problems/copy-list-with-random-pointer/description…

2023年1月7日:fastadmin导出数据为excel格式

需求图&#xff1a; 实现方法&#xff1a; 第一种方法&#xff1a;fastadmin自带导出数据&#xff0c;直接点击下载即可 效果图第二种方法&#xff1a;自定义导出按钮&#xff0c;需要编写方法 效果图&#xff1a; 效果图代码实现 首先&#xff1a;前端按钮代码(可直接拿来用…