通过实践带你揭开TCP中CLOSE_WAIT和TIME_WAIT的神秘面纱

linux服务器开发相关视频解析:

10道经典面试题的剖析, 技术方向如何决定职业方向

linux多线程之epoll原理剖析与reactor原理及应用

c/c++ linux服务器开发免费学习地址:c/c++ linux后台服务器高级架构师

CLOSE_WAIT和TIME_WAIT是如何产生的?大量的CLOSE_WAIT和TIME_WAIT又有何隐患?本文将通过实践角度来带你揭开CLOSE_WAIT和TIME_WAIT的神秘面纱!遇事不决先祭此图:

稍微补充一点:TIME_WAIT到CLOSED,这一步是超时自动迁移。

两条竖线分别是表示:

1、主动关闭(active close)的一方

2、被动关闭(passive close)的一方

网络上类似的图有很多,但是有的细节不够,有的存在误导。有的会把两条线分别标记成Client和Server。给读者造成困惑。对于断开连接这件事,客户端和服务端都能作为主动方发起,也就是「主动关闭」可以是客户端,可以是服务端。而对端相应的就是「被动关闭」。不管谁发起,状态迁移如上图。

1. 耗尽的是谁的端口?

首先解答初学者对socket的认识存在一个常见的误区。作为服务端,不管哪个WAIT都不会耗尽客户端的端口!

举个例子,我在某云的云主机上有个Server程序:echo_server。我启动它,监听2605端口。然后我在自己的MacBook上用telnet去连接它。连上之后,在云主机上用 netstat -anp看一下:

[guodong@yun test] netstat -anp|grep2 605

tcp 000.0.0.0:26050.0.0.0:*LISTEN3354/./echo_server

tcp 0172.12.0.2:2605xx.xx.xx.xx:31559ESTABLISHED3354/./echo_server

xx.xx.xx.xx是我Macbook的本机IP

其中有两条记录,LISTEN的表示是我的echo_server监听一个端口。ESTABLISHED表示已经有一个客户端连接了。第三列的IP端口是我echo_server的(这个显示IP是局域网的;第四列显示的是客户端的IP和端口,也就是我MacBook。

要说明的是这个端口:31559是客户端的。这个是建立连接时的MacBook分配的随机端口。

我们看一下echo_server占用的fd。使用 ls /proc/3354/fd -l 命令查看,其中 3354是echo_server的pid:

0-> /dev/pts/6

1-> /dev/pts/6

2-> /dev/pts/6

3-> anon_inode:[eventpoll]

4-> socket:[674802865]

5-> socket:[674804942]

0,1,2是三巨头(标准输入,输出,错误)自不必言。3是因为我使用了epoll,所以有一个epfd。

4其实就是我服务端监听端口打开的被动套接字;

5就是客户端建立连接到时候,分配给客户端的连接套接字。server程序只要给5这个fd写数据,就相当于返回数据给客户端。

服务端怎么会耗尽客户端的端口号的。这里消耗的其实是服务端的fd(也不是端口)!

【文章福利】需要C/C++ Linux服务器架构师学习资料加群812855908(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等)


2. 什么时候出现CLOSE_WAIT?

2.1 举个例子

回到我的MacBook终端,查看一下2605有关的连接(Mac上netstat不太好用,只能用lsof了):

[guodong@MacBooktest]lsof-iTCP:2605

COMMANDPIDUSERFDTYPEDEVICESIZE/OFFNODENAME

telnet74131guodong3uIPv40x199db390a76b3eb30t0TCP192.168.199.155:50307->yy.yy.yy.yy:nsc-posa(ESTABLISHED)

yy.yy.yy.yy表示的远程云主机的IP

nsc-posa其实就是端口2605,因为2605也是某个经典协议(NSC POSA)的默认端口,所以这种网络工具直接显示成了那个协议的名称。

客户端pid为74135。当然,我其实知道我是用telnet连接的,只是为了查pid的话,ps aux|grep telnet也可以。

注意:为了测试。我这里的echo_server是写的有问题的。就是没有处理客户端异常断开的事件。

下面我kill掉telnet(kill -9 74131)。再回到云主机查看一下:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN3354/./echo_server

tcp1172.12.0.2:2605xx.xx.xx.xx:31559CLOSE_WAIT3354/./echo_server

由于echo_server内没对连接异常进行侦测和处理。所以可以看到原先ESTABLISHED的连接变成了CLOSE_WAIT。并且会持续下去。我们再看一下它打开的fd:

0-> /dev/pts/6

1-> /dev/pts/6

2-> /dev/pts/6

3-> anon_inode:[eventpoll]

4-> socket:[674865719]

5-> socket:[674865835]

5这个fd还存在,并且会一直存在。所以当有大量CLOSE_WAIT的时候会占用服务器的fd。而一个机器能打开的fd数量是有限的。超过了,因为无法分配fd,就无法建立新连接啦!

2.2 怎么避免客户端异常断开时的服务端CLOSE_WAIT?

有一个方法。比如我用了epoll,那么我监听客户端连接套接字(5)的EPOLLRDHUP这个事件。当客户端意外断开时,这个事件就会被触发,触发之后。我们针对性的对这个fd(5)执行close()操作就可以了。改下代码,重新模拟一下上述流程,blabla细节略过。现在我们新echo_server启动。MacBook的telnet连接成功。然后我kill掉了telnet。观察一下云主机上的状况:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN7678/./echo_server

tcp1172.12.0.2:2605xx.xx.xx.xx:31559LAST_ACK

出现了LAST_ACK。我们看下fd。命令:ls /proc/7678/fd -l

0-> /dev/pts/6

1-> /dev/pts/6

2-> /dev/pts/6

3-> anon_inode:[eventpoll]

4-> socket:[674905737]

fd(5)其实已经关闭了。过一会我们重新netstat看下:

[guodong@yuntest]netstat-anp|grep2605

tcp000.0.0.0:26050.0.0.0:*LISTEN7678/./echo_server

LAST_ACK也消失了。为什么出现LAST_ACK。翻到开头,看我那张图啊!

CLOSE_WAIT不会自动消失,而LAST_TACK会超时自动消失,时间很短,即使在其存续期内,fd其实也是关闭状态。实际我这个简单的程序,测试的时候不会每次都捕捉到LAST_WAIT。有时候用netstat 命令查看的时候,就是最终那副图了。

3. 什么时候出现TIME_WAIT?

看我开篇那个图就知道了。

现在我kill掉我的echo_server!

[guodong@yuntest]netstat-anp|grep2605

tcp00172.17.0.2:2605xx.xx.xx.xx:51327TIME_WAIT

云主机上原先ESTABLISHED的那条瞬间变成TIME_WAIT了。

这个TIME_WAIT也是超时自动消失的。时间是2MSL。MSL是多长?

cat/proc/sys/net/ipv4/tcp_fin_timeout

一般是60。2MSL也就2分钟。在2分钟之内,对服务端有啥副作用吗?有,但问题不大。那就是这期间重新启动Server会报端口占用。这个等待,一方面是担心对方收不到自己的确认,等对方重发FIN。另一方面2MSL是报文的最长生命周期,可以避免Server重启(或其他Server绑同样端口)接收到了上一次的数据。

当然这个2MLS的等待,也可以通过给socket添加选项(SO_REUSEADDR)的方式来避免。Server可以立即重启(这样Server的监控进程就可以放心的重新拉起Server啦)。

通常情况下TIME_WAIT对服务端影响有限,而大量CLOSE_WAIT风险较高,但正确编写代码基本可以避免。为什么只说通常情况呢?因为生产环境是复杂的,一个服务通常会和多个下游服务用各种各样的协议进行通信。TIME_WAIT和CLOSE_WAIT在一些异常条件下,还是会触发的。

并不是说TIME_WAIT就真的无风险,其实无论是TIME_WAIT还是CLOSE_WAIT,永远记住当你的服务出现这两种现象的时候,它们只是某个问题导致的结果,而不是问题本身。有些网络教程教你怎么调大这个或那个的OS系统设置,个人感觉只是治标不治本。找到本质原因,避免TIME_WAIT和CLOSE_WAIT的产生,才是问题解决之道!

把这些了解清楚时候,是不是可以轻松应对什么4次挥手之类的面试题了?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 概述:作为一名运维工程师偶尔会遇到服务器出现大量TIME_WAIT或CLOSE_WAIT的连接状态。下面就来分析下...
    wangfs阅读 13,017评论 3 12
  • 1、TIME_WAIT状态存在的两个理由: 1)让4次握手关闭流程更加可靠;4次握手的最后一个ACK是是由主动关闭...
    _科长_阅读 1,159评论 0 0
  • 为什么要有TIME_WAIT呢? 1.可靠地实现TCP全双工连接的终止。A发送FIN到B,B收到FIN后发送ACK...
    Drama_Du阅读 763评论 0 0
  • linux和windows下TIME_WAIT过多的解决办法 如果使用了nginx代理,那么系统TIME_WAIT...
    嘿嘿逗阅读 909评论 0 0
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,531评论 28 53