第23章 TCP的保活定时器
所属:TCP/IP详解 卷1:协议 来源:TCP/IP详解 卷1:协议
本章介绍TCP的保活定时器,包括保活的用途、保活的争议和保活的实现等。
23.1 引言
保活定时器
保活定时器(Keepalive Timer):
- 也叫存活定时器
- 检测连接是否还活着
- 对方是不是还在
- 长时间没数据的时候用
保活定时器检测连接是否存活。
为什么需要保活
为什么需要保活:
场景:
- 客户端和服务器建立了连接
- 客户端突然崩溃了
- 服务器不知道
- 服务器还以为连接在
- 一直等
- 浪费资源
问题:
- TCP连接是虚拟的
- 不发数据就不知道对方还在不在
- 对方崩溃了,这边不知道
- 资源浪费
解决:
- 保活定时器
- 定期发保活探测
- 看对方有没有回应
- 没回应就认为连接断了
保活检测对方是否还活着。
保活的争议
保活的争议:
- 有人觉得保活好
- 有人觉得保活不好
- 有争议
支持的理由:
- 可以检测死连接
- 释放资源
- 防止资源泄漏
反对的理由:
- 浪费带宽
- 可能误判(网络暂时不通)
- 可能在计费网络上花钱
- TCP本来就不应该管这个
- 应该应用层自己处理
保活有争议。
本章讨论的内容
本章讨论的内容:
- 保活的用途
- 保活的争议
- 保活的实现
- 保活的参数
- 保活的例子
本章介绍保活定时器。
23.2 保活的用途
检测死连接
检测死连接:
- 对方崩溃了
- 对方断电了
- 对方网络断了
- 连接已经没用了
- 但这边还不知道
- 保活可以检测出来
检测对方是不是挂了。
防止连接被断开
防止连接被断开:
- 有些中间设备(比如NAT、防火墙)
- 会超时断开空闲的连接
- 保活可以保持连接活跃
- 不让中间设备断开
为什么中间设备会断开:
- 资源有限
- 空闲连接占资源
- 超时就断开
- 保活让连接看起来不空闲
保活防止中间设备断开。
服务器端的作用
服务器端的作用:
- 服务器有很多连接
- 有些客户端可能崩溃了
- 连接还占着
- 浪费服务器资源
- 保活可以清理死连接
服务器用保活清理死连接。
23.3 保活的争议
为什么有人反对
为什么有人反对保活:
-
浪费带宽
- 没事就发包
- 浪费网络资源
- 尤其是计费网络
-
可能误判
- 网络暂时拥塞
- 保活探测没收到回应
- 就断开了
- 其实连接还能用
-
TCP的职责
- 有人觉得TCP不应该管这个
- 这是应用层的事
- TCP只管可靠传输
- 不管连接活不活
-
计费问题
- 按流量计费的网络
- 保活包也要钱
- 白白花钱
反对的理由。
为什么有人支持
为什么有人支持保活:
-
检测死连接
- 对方崩溃了能检测到
- 释放资源
- 不然一直占着
-
防止中间设备断开
- NAT、防火墙超时
- 保活能保持连接
-
应用层简单
- 不用应用自己实现
- TCP提供了
- 方便
支持的理由。
默认是关闭的
默认是关闭的:
- 很多实现默认关闭保活
- 因为有争议
- 需要应用自己打开
- 用SO_KEEPALIVE选项
为什么默认关闭:
- 有争议
- 不是必须的
- 让应用自己决定
默认关闭,需要自己打开。
23.4 保活的实现
保活的参数
保活的参数:
-
保活时间(Keepalive Time)
- 连接空闲多久开始发探测
- 通常是2小时
- 7200秒
-
保活间隔(Keepalive Interval)
- 每次探测之间的间隔
- 通常是75秒
-
保活次数(Keepalive Probes)
- 发多少次探测没回应才断开
- 通常是9次
总时间:
- 2小时 + 9 × 75秒 = 2小时11分15秒
- 大约2小时11分钟
- 很长时间
保活参数。
保活的过程
保活的过程:
-
连接空闲
- 一段时间没有数据
- 保活时间到了
-
发探测包
- 发一个保活探测
- 就是一个空的ACK
- 序号是之前的减1
-
收到回应
- 对方回应了
- 连接还活着
- 重置定时器
- 再等保活时间
-
没收到回应
- 等保活间隔
- 再发一个探测
- 重复
-
多次没回应
- 发了N次都没回应
- 认为连接断了
- 关闭连接
保活的工作过程。
保活探测包
保活探测包:
- 一个空的ACK
- 序号比当前的小1
- 对方收到会回ACK
- 因为序号不对
- 但不影响数据
为什么序号减1:
- 确保对方会回应
- 即使没有新数据
- 也会回ACK
保活探测是序号减1的ACK。
几种情况
保活探测的几种结果:
-
对方正常
- 收到探测
- 回ACK
- 连接正常
- 重置定时器
-
对方崩溃了
- 没回应
- 多次探测都没回应
- 超时断开
-
对方崩溃后重启了
- 收到探测
- 不知道这个连接
- 回RST
- 连接复位
-
网络不通
- 探测包过不去
- 回应也回不来
- 多次探测没回应
- 超时断开
四种情况。
23.5 保活和应用层心跳
应用层心跳
应用层心跳(Application Heartbeat):
- 应用自己实现的保活
- 应用定期发心跳包
- 检测对方是否存活
- 比TCP保活更灵活
应用层也可以做心跳。
TCP保活 vs 应用层心跳
TCP保活 vs 应用层心跳:
| 对比项 | TCP保活 | 应用层心跳 |
|---|---|---|
| 实现位置 | TCP层 | 应用层 |
| 复杂度 | 简单,打开就行 | 复杂,自己实现 |
| 灵活性 | 低,参数固定 | 高,自己控制 |
| 功能 | 只能检测连接 | 可以检测应用状态 |
| 开销 | 小 | 大一些 |
| 跨平台 | 可能有差异 | 自己控制,一致 |
各有优缺点。
什么时候用哪个
什么时候用TCP保活:
- 简单需求
- 只要检测连接
- 不想自己实现
- 快速实现
什么时候用应用层心跳:
- 需要更灵活
- 需要检测应用状态
- 参数要自定义
- 跨平台一致性
根据需求选择。
23.6 小结
保活定时器概述
-
什么是保活定时器
- 检测连接是否存活
- 长时间没数据时用
-
为什么需要
- 对方崩溃了不知道
- 浪费资源
- 保活可以检测
-
争议
- 有人觉得好
- 有人觉得不好
- 默认关闭
保活的用途
-
检测死连接
- 对方崩溃、断电、断网
- 检测出来释放资源
-
防止中间设备断开
- NAT、防火墙超时
- 保活保持连接活跃
-
服务器端
- 清理死连接
- 释放资源
保活的争议
-
反对的理由
- 浪费带宽
- 可能误判
- 不是TCP的职责
- 计费问题
-
支持的理由
- 检测死连接
- 防止中间设备断开
- 应用层简单
-
默认关闭
- 有争议
- 需要自己打开
- SO_KEEPALIVE
保活的实现
-
参数
- 保活时间:通常2小时
- 保活间隔:通常75秒
- 保活次数:通常9次
-
过程
- 空闲到时间发探测
- 收到回应重置
- 没回应继续发
- 多次没回应断开
-
探测包
- 空的ACK
- 序号减1
-
四种结果
- 对方正常:回ACK
- 对方崩溃:没回应
- 对方重启:回RST
- 网络不通:没回应
应用层心跳
-
什么是应用层心跳
- 应用自己实现
- 更灵活
-
vs TCP保活
- TCP保活简单
- 应用层灵活
-
选择
- 简单需求用TCP保活
- 复杂需求用应用层心跳
关键概念
-
保活定时器
- 检测连接存活
- 有争议
-
保活参数
- 时间、间隔、次数
- 通常2小时开始
-
保活探测
- 序号减1的ACK
- 对方必须回应
-
应用层心跳
- 应用自己实现
- 更灵活
TCP keepalive