Netty空闲检测Keepalive

文章目录

  • 前言
  • 一、空闲检测
  • 二、Keepalive机制
  • 总结


前言

Netty的空闲检测和Keepalive机制都是为了确保客户端和服务器之间的连接仍然有效,防止连接断开。但它们在实现方式和原理上有所不同。

Netty的空闲检测机制是一种自定义的、基于应用层的机制。它主要通过定时发送和接收特定的消息(心跳包)来检测连接是否仍然处于活动状态。具体来说,Netty提供了IdleStateHandler类来实现心跳检测。在初始化ChannelPipeline时,我们可以添加IdleStateHandler实例,并设置读、写超时时间。当在指定时间内没有读或写操作时,IdleStateHandler会触发相应的事件。然后,我们可以添加一个自定义的事件处理类来处理这些事件,当检测到空闲状态时,发送心跳检测信息或者断开连接。

而Keepalive机制则是TCP/IP协议栈提供的一种机制,它依赖于操作系统实现。当TCP连接建立后,如果一段时间内(通常是2小时)双方都没有数据交互,那么操作系统会自动发送一个探测帧(keepalive probe)来查看对方是否还在线。如果对方无响应,操作系统会多次发送探测帧,直到确定连接已经断开。这种机制无需应用程序干预,但缺点是默认的心跳时间可能较长,不够灵活。

在Netty中,我们可以选择使用空闲检测机制或Keepalive机制,或者同时使用两者来确保连接的稳定性。具体选择哪种方式,需要根据应用的具体需求和网络环境来决定。例如,如果应用对连接的实时性要求较高,或者网络环境不稳定,可能需要使用更频繁的空闲检测;而如果应用主要处理长时间无交互的连接,或者对操作系统的默认心跳时间满意,那么可以选择使用Keepalive机制。


一、空闲检测

Netty中使用了IdleStateHandler来进行空闲检测,客户端和服务端保持长连接需要通过一个检测机制来确保链接的有效性,在链接处于空闲状态或者一方宕机又或者网络延迟,在这种情况下就要确认链接是否有效,无效链接就需要客户端和服务端都关闭当前链路,释放文件句柄资源。

IdleStateHandler 有三个主要参数:

  • readerIdleTime:一个IdleStateEvent,其状态是IdleState.READER_IDLE时的指定时间段内,没有执行读操作将被触发。 指定0以禁用。
  • writerIdleTime:一个IdleStateEvent,其状态是IdleState.WRITER_IDLE时的指定时间段内,没有执行写操作将被触发。 指定0以禁用。
  • allIdleTime:一个IdleStateEvent,其状态是IdleState.ALL_IDLE时的指定时间段内,没有进行读取和写入都将被触发。 指定0以禁用

其默认单位是秒,当然也有可以指定单位的构造,还能附带考虑buf处理数据时间的构造,这里就不多介绍了。

    public IdleStateHandler(long readerIdleTime, long writerIdleTime, long allIdleTime,TimeUnit unit) {this(false, readerIdleTime, writerIdleTime, allIdleTime, unit);}

通常我们在实现idle检测时,需要对IdleStateHandler 进行扩展,来满足我们的业务需求,代码如下:

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;import java.util.concurrent.TimeUnit;
/*** idle检测**/
@Slf4j
public class ServerIdleCheckHandler extends IdleStateHandler {public ServerIdleCheckHandler() {super(0, 0, 120, TimeUnit.SECONDS);}@Overrideprotected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) throws Exception {if (evt == IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT) {log.info("idle check happen, so close the connection");ctx.close();return;}super.channelIdle(ctx, evt);}
}

实现机制:

  • IdleStateHandler 的实现基于 EventLoop 的定时任务,每次读写都会记录一个值,在定时任务运行的时候,通过计算当前时间和设置时间和上次事件发生时间的结果,来判断是否空闲。

  • 内部有 3 个定时任务,分别对应读事件、写事件、读写事件。通常用户监听读写事件就足够了。

   private final class ReaderIdleTimeoutTask extends AbstractIdleTask {ReaderIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);}@Overrideprotected void run(ChannelHandlerContext ctx) {long nextDelay = readerIdleTimeNanos;if (!reading) {nextDelay -= ticksInNanos() - lastReadTime;}if (nextDelay <= 0) {// Reader is idle - set a new timeout and notify the callback.readerIdleTimeout = schedule(ctx, this, readerIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first = firstReaderIdleEvent;firstReaderIdleEvent = false;try {IdleStateEvent event = newIdleStateEvent(IdleState.READER_IDLE, first);channelIdle(ctx, event);} catch (Throwable t) {ctx.fireExceptionCaught(t);}} else {// Read occurred before the timeout - set a new timeout with shorter delay.readerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);}}}private final class WriterIdleTimeoutTask extends AbstractIdleTask {WriterIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);}@Overrideprotected void run(ChannelHandlerContext ctx) {long lastWriteTime = IdleStateHandler.this.lastWriteTime;long nextDelay = writerIdleTimeNanos - (ticksInNanos() - lastWriteTime);if (nextDelay <= 0) {// Writer is idle - set a new timeout and notify the callback.writerIdleTimeout = schedule(ctx, this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first = firstWriterIdleEvent;firstWriterIdleEvent = false;try {if (hasOutputChanged(ctx, first)) {return;}IdleStateEvent event = newIdleStateEvent(IdleState.WRITER_IDLE, first);channelIdle(ctx, event);} catch (Throwable t) {ctx.fireExceptionCaught(t);}} else {// Write occurred before the timeout - set a new timeout with shorter delay.writerIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);}}}private final class AllIdleTimeoutTask extends AbstractIdleTask {AllIdleTimeoutTask(ChannelHandlerContext ctx) {super(ctx);}@Overrideprotected void run(ChannelHandlerContext ctx) {long nextDelay = allIdleTimeNanos;if (!reading) {nextDelay -= ticksInNanos() - Math.max(lastReadTime, lastWriteTime);}if (nextDelay <= 0) {// Both reader and writer are idle - set a new timeout and// notify the callback.allIdleTimeout = schedule(ctx, this, allIdleTimeNanos, TimeUnit.NANOSECONDS);boolean first = firstAllIdleEvent;firstAllIdleEvent = false;try {if (hasOutputChanged(ctx, first)) {return;}IdleStateEvent event = newIdleStateEvent(IdleState.ALL_IDLE, first);channelIdle(ctx, event);} catch (Throwable t) {ctx.fireExceptionCaught(t);}} else {// Either read or write occurred before the timeout - set a new// timeout with shorter delay.allIdleTimeout = schedule(ctx, this, nextDelay, TimeUnit.NANOSECONDS);}}}

二、Keepalive机制

Netty本身并不直接提供Keepalive机制,因为Keepalive是TCP/IP协议栈的一部分,由操作系统实现。TCP Keepalive机制用于检测连接的死活,通过在一定时间内没有数据交互时,自动发送探测包来确认对方是否仍然在线。如果探测包没有得到响应,操作系统会多次尝试,直到确定连接已经断开。

在Netty中,你无法直接配置或控制TCP Keepalive机制,因为它是由底层操作系统和网络栈管理的。然而,你可以通过配置操作系统的网络设置来启用或调整TCP Keepalive的相关参数。

如果你希望在Netty中实现类似Keepalive的心跳检测机制,你需要在应用层自己实现。这通常通过定时发送和接收特定的心跳消息来完成。Netty提供了强大的定时器和事件驱动模型,使得在应用层实现心跳检测变得相对简单。你可以使用Netty的定时任务功能(如HashedWheelTimer)来定期发送心跳消息,并在接收到心跳响应时进行相应的处理。

总结来说,Netty本身不直接提供Keepalive机制,但你可以在应用层使用Netty的功能来实现类似的心跳检测机制,以确保连接的稳定性。同时,你也可以通过配置操作系统来启用和调整TCP Keepalive的相关参数。选择使用哪种方式取决于你的具体需求和网络环境。

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;@Slf4j
@ChannelHandler.Sharable
public class KeepaliveHandler extends ChannelInboundHandlerAdapter {@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {if (evt == IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT) {log.info("all idle happen. so need to send keepalive to keep connection not closed by server");ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);}super.userEventTriggered(ctx, evt);}
}

总结

Keepalive模式与空闲检测的结合在网络连接管理中具有显著的优势。以下是它们结合使用的主要优势:

  • 提高连接的稳定性:Keepalive模式通过定期发送探测帧来检查连接是否仍然有效,这有助于及时发现并处理因网络故障或对方主机崩溃导致的连接中断。而空闲检测则可以监测长时间没有数据传输的连接,确保这些连接不会因为长时间的静默而被误判为已断开。两者的结合使用可以大大提高连接的稳定性,减少不必要的连接中断。
  • 优化资源利用:空闲检测机制有助于识别并关闭长时间未使用的连接,从而释放服务器资源,如内存和处理能力。这对于资源有限的服务器环境尤为重要,可以避免资源浪费,提高资源利用率。同时,Keepalive模式可以减少因频繁创建和关闭连接而产生的开销,进一步提高系统性能。
  • 客户端加上空闲检测+keepalive 客户端在设定的时间内不发送数据就发送一个心跳信号。避免连接被断开,启用不频繁的心跳。
  • 提高用户体验:对于依赖网络连接的应用程序来说,稳定的连接和良好的性能是提升用户体验的关键因素。Keepalive模式与空闲检测的结合使用可以确保应用程序在网络环境不稳定时仍然能够保持有效的连接,减少因连接问题导致的用户体验下降。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/785629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

halcon图像膨胀

1、原理&#xff1a; 使用结构元素在图像上移动&#xff0c;如果结构元素中有任意一个像素和图像上的非零像素重叠&#xff0c;则保留此时结构元素中心所在位置&#xff0c;并将其像素值设置为非零。 2、halcon代码 其中圆形结构元素可设置半径&#xff0c;矩形结构元素设置…

Leetcode509——斐波那契数(C语言)

题目来源&#xff1a;509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 方法一&#xff1a;&#xff08;动态规划&#xff09; 首先找到斐波那契数的边界条件F(0)0 和 F(1)1。 当n>1时&#xff0c;每项的和都等于前两项的和&#xff0c;即&#xff1a;F(n)F(n−1)F(…

设计模式(7):装饰器模式

一.装饰器模式职责&#xff1a; 动态的为一个对象增加新的功能&#xff1b;装饰器是一种用于代替继承的技术&#xff0c;无须通过继承增加子类就能扩展对象的新功能&#xff0c;使用对象的关联关系代替继承关系&#xff0c;更加灵活&#xff0c;同时避免类型体系的快速膨胀。 …

MySQL故障排查与生产环境优化

一、MySQL单实例常见故障 1.逻辑架构图 MySQL逻辑架构图客户端和连接服务核心服务功能存储引擎层数据存储层 2.故障一 故障现象 ERROR 2002 (HY000): Cant connect to local MySQL server through socket/data/mysql/mysql.sock(2) 问题分析 数据库未启动或者数据库端口…

C++ 数学函数、头文件及布尔类型详解

C 数学 C 有许多函数可以让您在数字上执行数学任务。 最大值和最小值 max(x, y) 函数可用于找到 x 和 y 的最大值&#xff1a; 示例 cout << max(5, 10);而 min(x, y) 函数可用于找到 x 和 y 的最小值&#xff1a; 示例 cout << min(5, 10);C <cmath>…

Yolo 自制数据集dect训练改进

上一文请看 Yolo自制detect训练-CSDN博客 简介 如下图&#xff1a; 首先看一下每个图的含义 loss loss分为cls_loss, box_loss, obj_loss三部分。 cls_loss用于监督类别分类&#xff0c;计算锚框与对应的标定分类是否正确。 box_loss用于监督检测框的回归&#xff0c;预测框…

蓝桥杯真题:成绩统计

这题思路简单&#xff0c;但是输出结果的位置容易出错&#xff0c;题目要求四舍五入&#xff0c;所以要用Math.round&#xff08;&#xff09;的方法

Python快速入门系列-7(Python Web开发与框架介绍)

第七章:Python Web开发与框架介绍 7.1 Flask与Django简介7.1.1 Flask框架Flask的特点Flask的安装一个简单的Flask应用示例7.1.2 Django框架Django的特点Django的安装一个简单的Django应用示例7.2 前后端交互与数据传输7.2.1 前后端交互7.2.2 数据传输格式7.2.3 示例:使用Flas…

解决GNU Radio+USRP实现OFDM收发在接收端存在误码问题

文章目录 前言一、OFDM 收发流程1、OFDM 收端流程2、OFDM 收端流程 二、问题所在1、find_trigger_signal 函数解读2、general_work 函数3、问题所在 三、修改源码四、运行结果1、频谱2、传输数据测试 五、调试小技巧六、资源自取 前言 在使用 GNU Radio 时使用官方例程搭建 GN…

git clone没有权限的解决方法

一般情况 git clone时没有权限&#xff0c;一般是因为在代码库平台上没有配置本地电脑的id_rsa.pub 只要配置上&#xff0c;一般就可以正常下载了。 非一般情况 但是也有即使配置了id_rsa.pub后&#xff0c;仍然无法clone代码的情况。如下 原因 这种情况是因为ssh客户端…

前端常用代码整理— js,jquery篇(3)

目录 1.判断是否是json字符串 2.获取当前网址 3.将文本复制到剪贴板 4.获取一个月的天数 5.展平数组 6.要修改getRandomItem函数以返回数组中的随机两个元素&#xff0c;可以尝试以下代码 1.判断是否是json字符串 const isJson str > {try {JSON.parse(str);return …

Java面试题(含答案)4.多线程与并发篇

Java多线程与并发编程是一个广泛而深入的主题&#xff0c;因此涵盖所有可能的面试题和答案是不切实际的。不过&#xff0c;我可以为您提供一些常见的Java多线程与并发编程面试题及其答案&#xff0c;以帮助您准备面试。 面试题1&#xff1a;什么是Java中的线程&#xff1f; 答…

uniapp项目--青年帮新闻项目

文章目录 uniapp项目--青年帮新闻项目1.项目提要2.实际代码 uniapp项目–青年帮新闻项目 1.项目提要 导航滚动实现滚动条消失&#xff0c;使用的效果是渗透。 /deep/ ::-webkit-scrollbar {width: 4px !important;height: 1px !important;overflow: auto !important;backgroun…

Python:文件读写

一、TXT文件读写 Python中用open()函数来读写文本文件&#xff0c;返回文件对象&#xff0c;以下是函数语法。 open(<name>, <mode>, <buffering>&#xff0c;<encoding)name&#xff1a;文件名。 mode&#xff1a;打开文件模式。 buffering&#xff1a;设…

通过 Cookie、Session 和 Spring 拦截器技术,实现对用户登录状态的持有和清理(一)

本篇博客对应“2.3 会话管理”小节 视频名称&#xff1a;会话管理 视频链接 什么是HTPP协议&#xff1f; HTTP&#xff0c;Hpyer Text Transfer Protocl&#xff1a;定义了浏览器怎样从&#xff08;万维网客户进程&#xff09;怎样向Web服务器&#xff08;万维网服务器&#…

vue 文件下载

1.返回路径下载 注: 针对一些浏览器无法识别的文件格式&#xff08;如pdf、xls、ppt&#xff09;。可以直接在地址栏上输入URL即可触发浏览器的下载功能。 情况1 //地址栏输入文件URLwindow.location.href URLwindow.open(URL) 注:该方式将下载逻辑放在后端处理&#xff0c…

Mysql的高级语句3

目录 一、子查询 注意&#xff1a;子语句可以与主语句所查询的表相同&#xff0c;但是也可以是不同表。 1、select in 1.1 相同表查询 1.2 多表查询 2、not in 取反&#xff0c;就是将子查询结果&#xff0c;进行取反处理 3、insert into in 4、update…

IO练习题

1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中 #include <myhead.h>//文件IO实现文件拷…

实现offsetof宏以及交换一个整数二进制奇偶位的宏

目录 1. offsetof宏2. 交换奇偶位 1. offsetof宏 我们想用宏来实现offsetof函数,首先要了解这个函数的用法。 1.1 offsetof函数的介绍及用法 &#xff08;1&#xff09;功能&#xff1a;用来计算结构体中一个成员在该结构体中的相对起始位置的偏移量&#xff0c;单位是字节。 …

ClamAV:Linux服务器杀毒扫描工具

Clam AntiVirus&#xff08;ClamAV&#xff09;是免费而且开放源代码的防毒软件&#xff0c;软件与病毒码的更新皆由社群免费发布。ClamAV在命令行下运行&#xff0c;它不将杀毒作为主要功能&#xff0c;默认只能查出系统内的病毒&#xff0c;但是无法清除。需要用户自行对病毒…