IdleStateHandler 心跳作用:
心跳其实就是一个普通的请求,特点数据简单,业务也简单
心跳对于服务端来说,定时清除闲置会话inactive(netty5)、 channelclose(netty3)
心跳对客户端来说,用来检测会话是否断开,是否重连! 用来检测网络延时!
代码案例
Netty3.X
channelPipeline.addLast("Idle", new IdleStateHandler(new HashedWheelTimer(), 5, 5, 10));
第一个5: 5s内是否有读操作
第二个5:5s内是否有回写操作
第三个: 10s内是否有读写操作
如果玩家超时,使用channelFuture.addListener 通知玩家后,关闭连接。
if (e.getState() == IdleState.ALL_IDLE) {
System.out.println("踢玩家下线!");
ChannelFuture channelFuture = ctx.getChannel().write("timeout, you will close!");
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
future.getChannel().close();
}
});
package com.john.netty.learn.ch06.netty3.x;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelSink;
import org.jboss.netty.channel.Channels;
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.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
public class HeartBeatServer {
public HeartBeatServer(int port) {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.setFactory(new NioServerSocketChannelFactory(boss, workers));
serverBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.pipeline();
channelPipeline.addLast("Idle", new IdleStateHandler(new HashedWheelTimer(), 5, 5, 10));
channelPipeline.addLast("Decoder", new StringDecoder());
channelPipeline.addLast("HelloWorldHandler", new HeartBeatChannelHandler());
channelPipeline.addLast("Encoder", new StringEncoder());
return channelPipeline;
}
});
serverBootstrap.bind(new InetSocketAddress(port));
}
private ExecutorService boss = Executors.newCachedThreadPool();
private ExecutorService workers = Executors.newCachedThreadPool();
public static void main(String[] args) {
new HeartBeatServer(23);
}
}
package com.john.netty.learn.ch06.netty3.x;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
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.IdleStateAwareChannelHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
public class HeartBeatChannelHandler extends IdleStateAwareChannelHandler implements ChannelHandler {
public HeartBeatChannelHandler() {
}
@Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
System.out.println("channelIdle " + e.getState() + " time:" + new SimpleDateFormat("ss").format(new Date()));
if (e.getState() == IdleState.ALL_IDLE) {
System.out.println("踢玩家下线!");
ChannelFuture channelFuture = ctx.getChannel().write("timeout, you will close!");
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
future.getChannel().close();
}
});
}
}
/**
* 接收到消息
*/
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
// 没有过滤器
// ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();
// System.out.println("接收到消息:" + new String(channelBuffer.array()));
// 回写数据
// ctx.getChannel().write(ChannelBuffers.wrappedBuffer(("Hi " +
// e.getMessage()).getBytes()));
// channelPipeline.addLast("Decoder", new StringDecoder());
System.out.println("接收到消息:" + e.getMessage());
// channelPipeline.addLast("Encoder", new StringEncoder());
ctx.getChannel().write("Hi " + e.getMessage());
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelConnected");
super.channelConnected(ctx, e);
}
/**
* 建立Channel成功,关闭通道时候,才会触发Disconnect
*/
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelDisconnected");
super.channelDisconnected(ctx, e);
}
/**
* Channel 关闭
*/
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("channelClosed");
super.channelClosed(ctx, e);
}
/**
* 捕获异常
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
e.getCause().printStackTrace();
super.exceptionCaught(ctx, e);
}
}
--------------------------------------------------------------------------------------------------------------------------------
Netty5
Server :
ch.pipeline().addLast(new IdleStateHandler(5, 5, 10));
Handler :
if (e.state() == IdleState.ALL_IDLE) {
System.out.println("踢玩家下线!");
ChannelFuture channelFuture = ctx.writeAndFlush("timeout, you will close!");
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
future.channel().close();
}
});
package com.john.netty.learn.ch06.netty5.x;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
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.IdleStateHandler;
public class Netty5HeartBeatServer {
private int port;
public Netty5HeartBeatServer(int port) {
this.port = port;
}
public void start() throws InterruptedException {
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup workers = new NioEventLoopGroup();
try {
// 设置线程池
serverBootstrap.group(boss, workers);
// 设置socket工厂
serverBootstrap.channel(NioServerSocketChannel.class);
// 设置管道工厂
serverBootstrap.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 HeartBeatServerHandler());
}
});
serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048);// serverSocketchannel的设置,链接缓冲池的大小
// (未完成Accept操作,等待Socket Accept)
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);// socketchannel的设置,维持链接的活跃,清除死链接
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);// socketchannel的设置,关闭延迟发送
// 绑定端口
ChannelFuture channelFuture = serverBootstrap.bind(port);
System.out.println("start server " + port);
// 等待服务端关闭
channelFuture.channel().closeFuture().sync();
} finally {
boss.shutdownGracefully();
workers.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new Netty5HeartBeatServer(23).start();
}
}
package com.john.netty.learn.ch06.netty5.x;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
public class HeartBeatServerHandler extends SimpleChannelInboundHandler<String> {
public HeartBeatServerHandler() {
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
channelIdle(ctx, (IdleStateEvent) evt);
return;
}
super.userEventTriggered(ctx, evt);
}
protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) throws Exception {
if (e.state() == IdleState.ALL_IDLE) {
System.out.println("踢玩家下线!");
ChannelFuture channelFuture = ctx.writeAndFlush("timeout, you will close!");
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
future.channel().close();
}
});
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Read message " + msg);
ctx.writeAndFlush("Hi " + msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive(ChannelHandlerContext " + ctx + ")");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive(ChannelHandlerContext " + ctx + ")");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
所有源码下载 :https://download.youkuaiyun.com/download/netcobol/10308871