网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

10 | TIME_WAIT:隐藏在细节下的魔鬼

盛延敏 2019-08-23
你好,我是盛延敏,这是网络编程实战的第 10 讲,欢迎回来。
在前面的基础篇里,我们对网络编程涉及到的基础知识进行了梳理,主要内容包括 C/S 编程模型、TCP 协议、UDP 协议和本地套接字等内容。在提高篇里,我将结合我的经验,引导你对 TCP 和 UDP 进行更深入的理解。
学习完提高篇之后,我希望你对如何提高 TCP 及 UDP 程序的健壮性有一个全面清晰的认识,从而为深入理解性能篇打下良好的基础。
在前面的基础篇里,我们了解了 TCP 四次挥手,在四次挥手的过程中,发起连接断开的一方会有一段时间处于 TIME_WAIT 的状态,你知道 TIME_WAIT 是用来做什么的么?在面试和实战中,TIME_WAIT 相关的问题始终是绕不过去的一道难题。下面就请跟随我,一起找出隐藏在细节下的魔鬼吧。

TIME_WAIT 发生的场景

让我们先从一例线上故障说起。在一次升级线上应用服务之后,我们发现该服务的可用性变得时好时坏,一段时间可以对外提供服务,一段时间突然又不可以,大家都百思不得其解。运维同学登录到服务所在的主机上,使用 netstat 命令查看后才发现,主机上有成千上万处于 TIME_WAIT 状态的连接。
经过层层剖析后,我们发现罪魁祸首就是 TIME_WAIT。为什么呢?我们这个应用服务需要通过发起 TCP 连接对外提供服务。每个连接会占用一个本地端口,当在高并发的情况下,TIME_WAIT 状态的连接过多,多到把本机可用的端口耗尽,应用服务对外表现的症状,就是不能正常工作了。当过了一段时间之后,处于 TIME_WAIT 的连接被系统回收并关闭后,释放出本地端口可供使用,应用服务对外表现为,可以正常工作。这样周而复始,便会出现了一会儿不可以,过一两分钟又可以正常工作的现象。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(42)

  • Leon📷 置顶
    net.ipv4.tcp_tw_recycle是客户端和服务器端都可以复用,但是容易造成端口接收数据混乱,4.12内核直接砍掉了,老师是因为内核去掉了所以没提了嘛

    作者回复: BINGO。太多了,大家也不好接受,我想我还是不求面面俱到,但求有所启发和引领。

    2019-08-23
    5
  • 何某人
    老师,那么通过setsockopt设置SO_REUSEADDR这个方法呢?网上资料基本上都是通过设置这个来解决TIME_WAIT。这个方法有什么优劣吗?

    作者回复: 这个是解决端口复用的问题,并不是解决TIME_WAIT,这个是告诉内核,即使TIME_WAIT状态的套接字,我也可以继续使用它做为新的套集字使用。

    2019-08-23
    3
    9
  • alan
    TIME_WAIT的作用:
    1. 确保主动断开方的最后一个ACK成功发到对方
    2. 确保残留的TCP包自然消亡
    2019-08-23
    1
    5
  • magicnum
    1.记录一个值,比如60s,经过一个网关就减去一定短值,值=0的时候网关决定丢弃;
    2.不需要。timestamp不需要交互,只是发送方使用的
    2019-09-01
    1
    3
  • 吴光庆
    为什么是2MSL,不是3 MSL,4 MSL。

    作者回复: 因为是一来一返。

    2019-08-26
    1
    3
  • JasonZhi
    SO_REUSEADDR和SO_REUSEPORT可以详细说下作用吗?有点迷糊,文章都没有说明这两个参数,评论区就冒出一大堆关于这两个参数的评论。

    作者回复: 哈哈,提前剧透啊。

    这是为了解决如何快速复用处于TIME_WAIT的连接,如果不设置这个选项,处于TIME_WAIT的连接是不能被快速复用的,必须等待系统回收连接才可以,如果这个时候开启服务器端口,会报地址已被占用的错误。

    这块在第15讲里会有详细阐述。

    2019-09-10
    2
  • NeilMatthew
    TIME_WAIT的作用:
    1) 确保对方能够正确收到最后的ACK,帮助其关闭;
    2) 防迷走报文对程序带来的影响。
    TIME_WAIT的危害:
    1) 占用内存;
    2) 占用端口。

    作者回复: 总结很到位。

    2019-09-04
    1
    2
  • Geek_9a0180
    印象中是当一端关闭socket连接,另一端如果尝试从TCP连接中读取数据,则会报connect reset,如果偿试向连接中写入数据,则会报connect reset by peer,好像和老师说的正相反,还请老师帮忙解答一下,谢谢:)

    作者回复: 首先,我不明白connect reset和connect reset by peer有啥区别哎,这两个不是一回事么?都是RST信号。

    其次,我确认读的时候会读到FIN报文,连续写则会得到RST结果。

    2019-08-23
    1
    2
  • tongmin_tsai
    老师,我有疑问的是,IP包中TTL每经过一次路由就少1,那么2MSL怎么确保可以一定大于TTL的?

    作者回复: 只要每次经过一跳的时间肯定大于1秒以上就可以了,实际处理的时间肯定大于这个值的。

    2MSL设置的为60秒,TTL设置为60,只有每次一跳都大于1秒,那么肯定时间总和大于60秒了。

    2019-09-30
    1
    1
  • 网络人
    老师,能讲下windows平台下有没有提供更安全的选择呢?有没有类似的方法?可以提供代码参考下吗?

    作者回复: windows下没有研究过,不过应该大差不差的,类似的机制吧,你可以读读MSDN。

    2019-09-04
    1
  • 扬~
    当机器出现大量的time wait 状态,原因该如何排查呀,谢谢老师

    作者回复: netstat看一下,看看是什么进程,什么端口,为什么会有这个现象。

    2019-08-31
    1
    1
  • 沉淀的梦想
    使用SO_REUSEADDR和SO_REUSEPORT这两个选项是好的方法吗?

    作者回复: 大部分程序是需要这么干的,不是什么"坏"习惯。

    2019-08-24
    1
    1
  • 传说中的成大大
    关于第二个问题,思考了第二遍,因为是发送方的当前时间戳和从对方接受到的最新时间戳,如果接收方改了时间然后再从网络里面取出来自己上一次的发送的时间戳有很大差异就会出问题了,比如往前改或者往后改!最关键我觉得还是看怎么通过时间戳判断生存时间!
    2019-08-23
    1
  • 许童童
    1. MSL的意思是最长报文段寿命。IP头部中有个TTL字段意思是生存时间。TTL每经过一个路由器就减1,到0就会被丢弃,而MSL是由RFC里面规定的2分钟,但实际在工程上2分钟太长,因此TCP允许根据具体的情况配置大小,TTL与MSL是有关系的但不是简单的相等关系,MSL要大于TTL。MSL内部应该就是一个普通的定时器实现的。
    2.不需要统一时钟,可以在第一次交换双方的时钟,之后用相对时间就可以了。
    2019-08-23
    1
  • Dovelol
    老师好,想问个问题,一般我们服务器上运行一个服务,比如tomcat,zk这种,然后监听8080或2181端口,这时候外部直连(不再经过web服务器转发)的话,虽然有很多连接但服务端应该都是只占用一个端口,也就是说netstat -anp命令看到的本机都是ip+固定端口,那么此时如果服务端主动关闭一些连接的话,也会有大量time_wait问题对吧,但此时好像并没有消耗更多端口,那这个影响对于服务端来说是什么呢?老师讲的出现大量time_wait应该都是在客户端的一方吧,因为客户端发起请求会占用一个新端口,主动关闭到time_wait阶段就相当于这个新的端口一直被占用。我还有个疑问是,这种大量time_wait在连接数多的情况下是肯定会出现的,是不是可以从减少连接的方向去解决问题呢,比如用连接池这种技术可以解决吗?

    作者回复: 这个时候你看到的连接都是服务器端被动建立的连接,本地端口都是服务器监听的端口,类似
    <127.0.0.1, 80, ip1, 51231>
    <127.0.0.1, 80, ip2, 51331>
    ...
    所以,不会存在我讲到的那个问题,这些个连接过了一段时间自然会被回收。

    连接池是为了多个线程复用连接,减少TCP连接的数量,是为了更高效的使用TCP,确实也客观减少了连接的数量。

    2019-08-23
    3
    1
  • Geek_68d3d2
    我怎么感觉TIME_WAIT的那两个好处是一样的啊。A收到了FIN发送一个ACK,此时网络中由旧有的链接产生的报文就只剩一个ACK了吧,保证最后一个ACK能够到达对端和保证旧有连接产生的报文全部消失是一回事吧???

    作者回复: 不是的,旧连接产的报文消失和2MSL紧密有关,这是需要让连接推迟一段时间关闭;而ACK是为了维护连接的状态,相当于保持了一个连接的上下文信息。

    2019-12-05
  • Geek_68d3d2
    TIME_WAIT和2MSL是什么关系啊。TIME_WAIT的时间要么是60秒要么是2MSL吗?

    作者回复: 你可以简单理解为就是2MSL,时间约为60秒。

    2019-12-05
  • godtrue
    1:TIME_WAIT代表着什么?
    首先,TIME_WAIT是TCP连接的一种状态,且只有发起一次TCP连接终止的一方才会进入这种状态。
    这种状态表示等待被动关闭连接的一方正确关闭,这个等待时间是2MSL=60秒,另外,这个状态还起到让旧连接的重复分节在网络中自然消失的作用。
    MSL是最长分节生命周期时间=30秒,分节我没理解是什么意思?是指从一端发送一个可发送的最大消息嘛?
    如果让我想象的话,把一个TCP连接比喻为一根水管,现在想关闭这根水管的连接,一端会发送一个消息到另一端说他想断开连接,另一端接到消息后会把水管中的水处理完,然后发送一个消息说她知道了,由于这根水管是双向的,所以,被动关闭的一方也会发送一条消息告诉发起端,他的收尾工作做完了,现在处于可关闭状态,发起端收到消息后会发送一个确认关闭消息,然后等60秒,被动关闭端接受到响应消息后进入真正的关闭状态。
    我猜想一个TCP连接关闭的流程如此复杂,主要是因为两个原因,一是TCP连接传输的是字节流,不能说关就关,这样可能导致字节流信息的不完整,第二个原因是TCP连接是双工通信,两端都可读写,关闭的连接的动作需要双方配合,首先,知道这个连接要关闭了,就不再进行写操作了,另外,处理完此次的读操作。

    2:为啥会出现TIME_WAIT?
    参考1

    3:TIME_WAIT所带来的负面影响?
    只要进行TCP的连接断开操作,必然会出现TIME_WAIT这个状态,如果量少无所谓,反正一会就会消失,如果持续出现,且不断增长就会导致出现一些问题了,因为这个状态会占用内存空间,同时也会占用通信端口,内存空间的占用量比较少问题不大,不过端口资源的占用可能会导致无法创建新连接,这个就比较严重了,新连接不可创建意味着就不能进行连接和通信。我目前还没碰到过这种情况,看评论,又得到一个新的认知TCP的服务端监听的端口是唯一的,不过连接的端口是不确定的具体有内核决定用那个,这个要验证一下。

    4:设计TIME_WAIT这个状态是为了解决啥问题?
    参考1
    2019-11-23
  • wg1993
    MSL>=TTL,如果MSL=60s,TTL=60,老师在下面说是每次路由器转发时间都大于1s,保证时间肯定超过60s。。。个人感觉说反了吧,应该是每次转发时间都小于1s,保证即便经过60次转发时间也肯定小于60s。。。这个地方不太理解啊

    作者回复: 没有反啊,这里是说,假设TTL为60秒(这个是一个理论期望的固定值),那么由于经历了60次转发,导致MSL肯定大于60秒,所以MSL >= TTL必然成立。

    2019-11-18
  • 绿箭侠
    2MSL,总结的说,当出现网络包迷走,刚好当ack到达对端瞬间,对端发出另一个fin包,这样主动关闭方在网络包最大存活时间内接收到它并发出另一个ack,再重新计时,直到对端正常关闭?!!

    作者回复: 是的。

    2019-11-06
收起评论
42
返回
顶部