TCP四次挥手和TIME_WAIT

TCP四次挥手和TIME_WAITFIN_WAIT_1:FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情…

大家好,又见面了,我是你们的朋友全栈君。

TCP四次挥手和TIME_WAIT

 

TCP四次挥手和TIME_WAIT

FIN_WAIT_1 : FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是: FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方)

FIN_WAIT_2 :实际上FIN_WAIT_2状态下的SOCKET,表示半连接 ,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文 ,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)

CLOSING(比较少见) : 这种状态比较特殊,实际情况中应该是很少见。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT : 表示在等待关闭。当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

CLOSED: 表示连接中断。

 

同时关闭

TCP四次挥手和TIME_WAIT

 

 

 

 

为什么需要四次挥手?

那可能有人会有疑问,在tcp连接握手时为何ACK是和SYN一起发送,这里ACK却没有和FIN一起发送呢。原因是因为tcp是全双工模式,接收到FIN时意味将没有数据再发来,但是还是可以继续发送数据(解决全双工问题)。

 

 

 

TIME_WAIT

TIME_WAIT状态会持续2MSL的时间才会转换到CLOSE状态,一般是1-4分钟(现在对于linux是30秒)。MSL(最大分段生存期):指明TCP报文在Internet上最长生存时间。

 

只有主动关闭的一方才会进入TIME_WAIT状态。那么端口不够用就是文件描述符不够用了,因为文件描述符只有在从TIME_WAIT状态转换到CLOSE状态后才会真正被系统收回。

 

 

问题

 

TCP四次挥手和TIME_WAIT

如果执行主动关闭的一方HOST1不进入到TIME_WAIT状态就关闭连接那会发生什么呢?

当重传的FIN消息到达时,因为TCP已经不再有连接的信息了,所以就用RST(重新启动)消息应答,导致HOST2进入错误的状态而不是有序终止状态(如果主动关闭的一方又开启了一个新的链接,则重发的FIN会将新连接给关闭掉),如果发送最后ACK消息的一方HOST1处于TIME_WAIT状态并仍然记录着连接的信息,它就可以正确的响应HOST2的FIN消息了。(最后一个ACK可能丢失并导致HOST2重新发送FIN消息,导致老连接的包会干扰新连接

 

 

TIME_WAIT占用的资源

1、TW会占用内存,但是占用内存很小(1W的TW连接占用1M左右)

2、对CPU也是有影响的,比如TW的端口太多,导致选择可用端口时,需要很多次选择才能成功;但这个影响也是很小的。

3、TW连接会占用大量端口。

4、被占用的是一个五元组:(协议,本地IP,本地端口,远程IP,远程端口)。对于Web 服务器,协议是TCP,本地IP通常也只有一个,本地端口默认的80或者443。只剩下远程 IP和远程端口可以变了。如果远程IP相同的话,就只有远程端口可以变了。这个只有几万个(net.ipv4.ip_local_port_range),所以当同一客户端向服务器建立了大量连接之后,会耗尽可用的五元组导致问题。

 

https://www.zhihu.com/question/29354418?sort=created

http://www.cnblogs.com/lulu/p/4149312.html

 

 

 

TIME_WAIT优化

tcp_timestamps

只有该选项开启了,tcp_tw_reuse和tcp_tw_recycle才能起作用。另外tcp_timestamps可以解决PAWS和计算RTT的问题。

 

tcp_tw_reuse

需要开启tcp_timestamps时才有效。针对于一个连接,如果开启了该开关,即便该连接处于TW状态,收到SYN包之后,也能建立一条新的连接。该连接跟之前的TW连接5元组相同。但是需要满足下面条件的其中一个:

1)初始化序列号比老的TW序列号大。

2)新来的连接的时间戳比老的TW的时间戳大。

 

tcp_tw_recycle

快速回收TW,应该是RTO时间内回收。需要开启tcp_timestamps时才有效。

即使快速回收之后,也保留了一些信息,保留的信息有:对端IP、最后的对端过来的时间戳等。对于新来的连接,同时满足下面3个条件时,连接会被拒绝;否则连接不会被拒绝:

1)来自该IP的TCP连接请求带有时间戳信息;

2)在MSL时间内,收到过该IP过来的数据;

3)新连接的时间戳小于保存的TW的时间戳;

 

tcp_max_tw_buckets

这个是控制并发的TIME_WAIT的数量,默认值是50几W,如果超限,那么,系统会把多的给destory掉,然后在日志里打一个警告。

 

SO_LINGER

struct linger {

    int l_onoff; /* 0 = off, nozero = on */

    int l_linger; /* linger time */

};

1)设置 l_onoff为0,则该选项关闭,l_linger的值被忽略,等于内核缺省情况,close调用会立即返回给调用者,如果可能将会传输任何未发送的数据。

2)设置 l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;(说明如果没有数据被丢弃,也是正常的四次挥手;不是rst)

3)设置 l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。

 

 

 

TCP关闭连接的方式

 

正常关闭

调用close()关闭socket、没close但进程正常结束(当然这是不应该的做法)、进程core掉、在shell 命令行中kill掉进程,都可抽象成“正常”关闭。因为即使core掉,内核也会马上帮应用程序回收(close)socket文件描述符。

 

不正常关闭

客户端崩溃了,此时肯定发不出FIN包了(当然啦,内核都没机会帮应用程序回收资源了)。这种情况,服务器端有如下两种情况。

1、服务器send数据,因为客户端已经崩溃,服务器收不到ACK自然会不停的重传。Berkeley的重传机制,重传8次,相对第一次传的15分钟后仍没收到ACK,则返回ETIMEDOUT或EHOSTUNREAC错误。如果服务器不理会这个错误,再次调用send,则立马返回Broken Pipe错误。

2、服务器不发任何数据了,那只有靠应用层心跳检测机制或Keepalive,来发觉TCP断连了。

 

参考资料

https://zhuanlan.zhihu.com/p/29334504

https://zhuanlan.zhihu.com/p/32386693

TCP四次挥手和TIME_WAIT

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/142632.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • goland2021破解激活码【在线注册码/序列号/破解码】「建议收藏」

    goland2021破解激活码【在线注册码/序列号/破解码】,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • gtest框架_软件测试框架

    gtest框架_软件测试框架gtest下载与安装gitclonehttps://github.com/google/googletest.gitcdgoogletestmkdirbuildcmake..makesudomakeinstall以上命令会将gtest编译好,并将动态链接库放在/usr/local/lib目录下:zhouhao@ubuntu:/usr/loc…

  • 详述ViewState用法

    详述ViewState用法与刚接触ASP.NET页面的开发人员交谈时,他们通常向我提出的第一个问题就是:“那个ViewState到底是什么?”他们的语气中流露出的那种感觉,就象我来到一家异国情调的餐馆,侍者端上一道我从未见过的菜肴时的那种感觉-既疑惑不解,又充满好奇。但肯定有人认为它不错,否则就不会提供了。所以,我会先尝一尝,或许会喜欢上它,尽管它看上去的确很古怪!对于ViewState也是如此,但是如果适应了它的风格,…

  • 如何安装Pycharm_pycharm安装教程2020

    如何安装Pycharm_pycharm安装教程2020安装方法:1、安装配置好Python环境;2、从官网下载pycharm安装程序;3、直接双击下载好的exe文件,进入安装向导界面,按照指示一步步操作;4、点击Install进行安装,等待安装完成后,点击Finish结束安装即可。本教程操作环境:windows7系统、Python3.5.2版本、DellG3电脑。首先我们来安装python1、首先进入网站下载:点击打开链接(或自己输入网址http…

  • 【超详细教程】Mac如何用QuickTime录屏soundflower录制屏内外声音(附视频演示教程)

    【超详细教程】Mac如何用QuickTime录屏soundflower录制屏内外声音(附视频演示教程)作者:齐木南子酱链接:http://www.i5seo.com/mac-own-software-recording-screen.html来源:长沙SEO霜天如何用mac自带软件录屏且录制屏内屏外声音?这个问题困扰了很多使用苹果mac笔记本的用户,本教程你能get到的3个技能点1.用macbook自带软件录屏(无屏内屏外声音)2.用macbook自带软件录屏+有屏内声音+…

  • 低通滤波器matlab代码_matlab设计fir低通滤波器

    低通滤波器matlab代码_matlab设计fir低通滤波器##一、获取代码方式**获取代码方式1:**完整代码已上传我的资源:[【滤波器】基于matlab低通滤波器(LPF)设计【含Matlab源码323期】](https://download.csdn.net/download/TIQCmatlab/31349826)

    2022年10月28日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号