心跳对于server来说可以定时的检测客户端是否存在清除闲置的链接
对于client 来说可以检测和服务器的链接是否中断,测试延迟,首先分析netty3 的心跳代码, netty3 和netty5 有一定的差异, netty5的封装度高
netty3
netty的心跳检测的核心类是 IdleStateEvent ,这个对象在netty3 中可以通过回掉函数handleUpstream 传递的 ChannelEvent 进行转换,通过getstate 方法可以返回心跳的状态 ,代码如下
package heartbeat;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author ZZQ
* @date 2018/8/11 20:16
*/
public class Server {
/**
* @author ZZQ
* @date 2018/8/11
* @description 服务器的心跳处理可以检测客户端是否存在,清理僵尸客户端
* 客户端的心跳可以检测和服务器是否链接
*/
public static void main(String[] args) {
ServerBootstrap bootstrap = new ServerBootstrap();
ExecutorService worker = Executors.newCachedThreadPool();
ExecutorService boss = Executors.newCachedThreadPool();
HashedWheelTimer hashedWheelTimer = new HashedWheelTimer();
//设置线程工厂
bootstrap.setFactory(new NioServerSocketChannelFactory(boss,worker));
bootstrap.setPipelineFactory(()->{
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("idle", new IdleStateHandler(hashedWheelTimer, 5, 5, 10));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("helloHandler", new HelloHandler());
return pipeline;
});
bootstrap.bind(new InetSocketAddress(8888));
System.out.println("start...");
}
static class HelloHandler extends SimpleChannelHandler{
/**
* @author ZZQ
* @date 2018/8/11
* @description 此回掉函数管理心跳事件
*/
@Override
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if(e instanceof IdleStateEvent) {
IdleState state = ((IdleStateEvent) e).getState();
if (state == IdleState.ALL_IDLE) {
System.out.println("提醒玩家下线");
ChannelFuture future = ctx.getChannel().write("time out ,you will close");
future.addListener((x) -> {
ctx.getChannel().close();
});
}
}else {
super.handleUpstream(ctx,e);
}
}
}
}
使用心跳回掉函数的之前在初始化管道工厂的时候要加入, 心跳函数的调用时间周期
pipeline.addLast("idle", new IdleStateHandler(hashedWheelTimer, 5, 5, 10));
netty5
netty5 废除了netty3 中的handleupstream方法, 提供userEventTriggered 这个回掉函数
源码上的说明, 如果一个用户事件被触发, 函数被调用 , 由此可知不止一个事件 代码如下
package com.zzq.Heartbeat;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import java.net.InetAddress;
/**
* @author ZZQ
* @date 2018/8/11 16:54
*/
public class Server {
public static void main(String[] args) {
//创建服务类
ServerBootstrap bootstrap = new ServerBootstrap() ;
//创建线程池
EventLoopGroup worker = new NioEventLoopGroup();
EventLoopGroup boss = new NioEventLoopGroup() ;
//设置线程池
bootstrap.group(boss,worker);
bootstrap.channel(NioServerSocketChannel.class);
//设置通道
bootstrap.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(5,5,10));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new StringEncoder());
ch.pipeline().addLast(new MyHandler());
}
});
bootstrap.bind(8888);
}
static class MyHandler extends SimpleChannelInboundHandler{
@Override
protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
if(idleStateEvent.state() == IdleState.ALL_IDLE){
ChannelFuture future = ctx.writeAndFlush("会话超时...");
future.addListener((x)->{
ctx.channel().close();
});
}
}
}
}
netty 是一款异步的事件驱动的网络应用程序框架, 支持快速的开发和可维护的高性能面向协议的服务器和客户端