传统的心跳包设计,基本上是服务端和客户端同时维护 Scheduler,然后双方互相接收心跳包信息,然后重置双方的上下线状态表。此种心跳方式的设计,可以选择在主线程上进行,也可以选择在心跳线程中进行,由于在进行业务调用过程中,此种心跳包是没有必要进行发送的,所以在一定程度上会造成资源浪费。严重的甚至会影响业务线程的操作。但是在 Netty 中是通过检测链路的空闲与否在进行的。链路分为读操作空闲,写操作空闲,读写操作空闲。由于空闲检测本身只有在通道空闲的时候才进行检测,而不是固定频率的进行心跳包通讯,所以可以节省网络带宽,同时对业务的影响也很小

在 Netty 中空闲检测需要引入 IdleStateHandler,然后实现自己的心跳处理 Handler,本文中服务端与客户端均向对方发送心跳包。

一、服务端

1.1 编解码及 Handler

...

.childHandler(new ChannelInitializer<SocketChannel>() {

    @Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("ping", new IdleStateHandler(10, 5, 10));
channel.pipeline().addLast("encoder", new NettyMessageEncoder());
channel.pipeline().addLast("decoder", new NettyMessageDecoder());
channel.pipeline().addLast("message", new MessageHandler());
channel.pipeline().addLast("heartbeat", new HeartbeatHandler());
}
}); ...

HeartbeatHandler 为 心跳处理 Handler

1.2 心跳处理 Handler

public class HeartbeatHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(HeartbeatHandler.class); private final AttributeKey<Integer> counterAttr = AttributeKey.valueOf(ChannelSupervise.COUNTER_ATTR);; @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
super.userEventTriggered(ctx, evt); if(evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent)evt;
switch (idleStateEvent.state()) {
case READER_IDLE:
NettyMessage<String> nettyMessage = new NettyMessage<>();
nettyMessage.setSessionId(0L);
nettyMessage.setType(NettyMessageTypeEnum.HEARTBEAT); ctx.writeAndFlush(nettyMessage).addListener(future -> {
// if(future.isSuccess()) {
// ctx.channel().attr(counterAttr).set(0);
// }else {
Integer counter = ctx.channel().attr(counterAttr).get();
counter = counter + 1;
LOGGER.info(ctx.channel().id().asShortText() + ",发送心跳: " + counter);
if(counter >= 3) {
ctx.close();
} else {
ctx.channel().attr(counterAttr).set(counter);
}
// }
});
break;
default:
break;
}
}
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().attr(counterAttr).set(0);
ChannelSupervise.addChannel(ctx.channel());
} @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ChannelSupervise.removeChannel(ctx.channel());
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ctx.channel().attr(counterAttr).set(0);
ctx.fireChannelRead(msg);
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
LOGGER.error("断开连接", cause);
ctx.close();
}
}

本例中,如果服务端连续发送三次心跳包,则认为客户端断开连接,使用 Netty 内置的 AttributeKey 计数 (本例中为方便测试注释掉部分代码,正常来说如果发送消息成功则证明客户端还在线,需要把计数重置为 0)。

二、客户端

2.1 编解码及 Handler

...

.handler(new ChannelInitializer<SocketChannel>() {

    @Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast("ping", new IdleStateHandler(5, 5, 3));
channel.pipeline().addLast("encoder", new NettyMessageEncoder());
channel.pipeline().addLast("decoder", new NettyMessageDecoder());
channel.pipeline().addLast("heartbeat", new HeartbeatHandler());
channel.pipeline().addLast("logger", new LoggingHandler(LogLevel.INFO));
}
}); ...

HeartbeatHandler 为 心跳处理 Handler

2.2 心跳处理 Handler

public class HeartbeatHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(HeartbeatHandler.class); @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if(evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt; switch (idleStateEvent.state()){
case WRITER_IDLE:
LOGGER.info("发送心跳包");
NettyMessage<String> nettyMessage = new NettyMessage<>();
nettyMessage.setSessionId(0L);
nettyMessage.setType(NettyMessageTypeEnum.HEARTBEAT);
ctx.writeAndFlush(nettyMessage).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
break;
default:
break;
}
} super.userEventTriggered(ctx, evt);
} ...
}

本例中,如果客户端发送心跳消息失败则断开连接。

参考

  1. Netty(一) SpringBoot 整合长连接心跳机制TCP-Heartbeat/)
  2. 微言Netty:分布式服务框架

完整代码:GitHub

Netty 心跳处理的更多相关文章

  1. 连接管理 与 Netty 心跳机制

    一.前言 踏踏实实,动手去做,talk is cheap, show me the code.先介绍下基础知识,然后做个心跳机制的Demo. 二.连接 长连接:在整个通讯过程,客户端和服务端只用一个S ...

  2. 聊聊心跳机制及netty心跳实现

    我们在使用netty的时候会使用一个参数,ChannelOption.SO_KEEPALIVE为true, 设置好了之后再Linux系统才会对keepalive生效,但是linux里边需要配置几个参数 ...

  3. NETTY 心跳机制

    最近工作比较忙,但闲暇之余还是看了阿里的冯家春(fengjiachun)的github上的开源代码Jupiter,写的RPC框架让我感叹人外有人,废话不多说,下面的代码全部截取自Jupiter,写了一 ...

  4. netty心跳检测机制

    既然是网络通信那么心跳检测肯定是离不开的,netty心跳检测分为读.写.全局 bootstrap.childHandler(new ChannelInitializer<SocketChanne ...

  5. netty心跳机制测试

    netty中有比较完善的心跳机制,(在基础server版本基础上[netty基础--基本收发])添加少量代码即可实现对心跳的监测和处理. 1 server端channel中加入心跳处理机制 // Id ...

  6. Netty心跳机制

    一.概念介绍网络中的接收和发送数据都是使用操作系统中的SOCKET进行实现.但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题.可是如何判断这个套接字是否还可以使用呢?这个就需要在系统 ...

  7. Netty 心跳服务之 IdleStateHandler 源码分析

    前言:Netty 提供的心跳介绍 Netty 作为一个网络框架,提供了诸多功能,比如我们之前说的编解码,Netty 准备很多现成的编解码器,同时,Netty 还为我们准备了网络中,非常重要的一个服务- ...

  8. Netty心跳简单Demo

    前面简单地了解了一下IdleStateHandler,我们现在写一个简单的心跳demo: 1)服务器端每隔5秒检测服务器端的读超时,如果5秒没有接受到客户端的写请求,也就说服务器端5秒没有收到读事件, ...

  9. Netty心跳之IdleStateHandler

    Netty提供了对心跳机制的天然支持,心跳可以检测远程端是否存活,或者活跃 今天我们就一起初识一下Netty4的心跳机制 Netty4.0提供了一个类,名为IdleStateHandler,这个类可以 ...

  10. netty心跳机制和断线重连(四)

    心跳是为了保证客户端和服务端的通信可用.因为各种原因客户端和服务端不能及时响应和接收信息.比如网络断开,停电 或者是客户端/服务端 高负载. 所以每隔一段时间 客户端发送心跳包到客户端  服务端做出心 ...

随机推荐

  1. nodejs中连接mongodb数据库

    const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/blog', { useNewUrlParser ...

  2. Inception系列之Inception_v1

    目前,神经网络模型为了得到更好的效果,越来越深和越来越宽的模型被提出.然而这样会带来以下几个问题: 1)参数量,计算量越来越大,在有限内存和算力的设备上,其应用也就越难以落地. 2)对于一些数据集较少 ...

  3. leetcode144add-two-numbers

    题目描述 给定两个代表非负数的链表,数字在链表中是反向存储的(链表头结点处的数字是个位数,第二个结点上的数字是十位数...),求这个两个数的和,结果也用链表表示. 输入:(2 -> 4 -> ...

  4. day86:luffy:前端发送请求生成订单&结算页面优惠劵的实现

    目录 1.前端发送请求生成订单 1.前端点击支付按钮生成订单 2.结算成功之后应该清除结算页面的数据 3.后端计算结算页面总原价格和总的真实价格并存到数据库订单表中 2.优惠劵 1.准备工作 2.前端 ...

  5. 把数据转化为JSON格式用ajax进行前后端交互

    接着在https://www.cnblogs.com/dong973711/p/10907733.html的基础上做验证. 从前端提交数据 前端页面,submit.html <!DOCTYPE ...

  6. Linux Capabilities 入门教程:进阶实战篇

    原文链接:https://fuckcloudnative.io/posts/linux-capabilities-in-practice-2/ 该系列文章总共分为三篇: Linux Capabilit ...

  7. 纯CSS实现3D正方体动画效果

    前言 纯CSS实现3D正方体动画效果,此方法是通过transform的旋转(rotate)和位移(translate)实现的,具体效果是鼠标滑过时正方体的一个面会产生位移 效果图 ​

  8. 内网安装python第三方包

    内网快速安装python第三方包 内网安装包是一个很麻烦的问题,很多时候,内网的源会出现问题,导致无法安装. 这里给出一种快速在内网中安装第三方包,无需使用内网的源. 外网操作 1.根据开发环境下的所 ...

  9. mybatis foreach collection

    原文传递:https://blog.csdn.net/qq_24084925/article/details/53790287 foreach元素的属性主要有 item,index,collectio ...

  10. Linux——CentOS 7 systemctl和防火墙firewalld命令

    一.防火墙的开启.关闭.禁用命令 (1)设置开机启用防火墙:systemctl enable firewalld.service (2)设置开机禁用防火墙:systemctl disable fire ...