Netty心跳检测
程序员文章站
2024-03-23 23:03:10
...
Netty心跳检测
网络连接中,处理Idle事件是很常见的,一般情况下,客户端与服务端在指定时间内没有任何读写请求,就会认为连接是idle的。此时,客户端需要向服务端发送ping消息,来维持服务端与客户端的链接。那么怎么判断客户端在指定时间里没有任何读写请求呢?
public class Client {
int port;
String host;
static final int WRITE_WAIT_SECONDS = 5;
public Client(int port,String host) {
// TODO Auto-generated constructor stub
this.host = host;
this.port = port;
}
public void connect() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
ch.pipeline().addLast("encoder", new ObjectEncoder());
ch.pipeline().addLast("ping", new IdleStateHandler(0, WRITE_WAIT_SECONDS, 0,TimeUnit.SECONDS));
ch.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws CloneNotSupportedException, InterruptedException {
Client client = new Client(4456, "127.0.0.1");
client.connect();
}
}
public class ClientHandler extends SimpleChannelInboundHandler<Object>{
int unRecPingTimes = 0 ;
@Override
protected void channelRead0(ChannelHandlerContext arg0, Object arg1) throws Exception {
System.out.println("超时");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.READER_IDLE) {
/*读超时*/
System.out.println("===服务端===(READER_IDLE 读超时)");
if (unRecPingTimes>=3) {
ctx.channel().close();
} else {
unRecPingTimes++;
}
} else if (event.state() == IdleState.WRITER_IDLE) {
/*写超时*/
System.out.println("===服务端===(WRITER_IDLE 写超时)");
} else if (event.state() == IdleState.ALL_IDLE) {
/*总超时*/
System.out.println("===服务端===(ALL_IDLE 总超时)");
}
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client Active()");
}
}
public class Server {
int port;
static final int READ_WAIT_SECONDS = 6;
public Server(int port) {
// TODO Auto-generated constructor stub
this.port = port;
}
public void start() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
//create ServerBootstrap instance
ServerBootstrap b = new ServerBootstrap();
//Specifies NIO transport, local socket address
//Adds handler to channel pipeline
b.group(group).channel(NioServerSocketChannel.class).localAddress(port)
.childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast("decoder", new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
ch.pipeline().addLast("encoder", new ObjectEncoder());
/*
* 这里只监听读操作
* 可以根据需求,监听写操作和总得操作
*/
ch.pipeline().addLast("pong", new IdleStateHandler(READ_WAIT_SECONDS, 0, 0,TimeUnit.SECONDS));
ch.pipeline().addLast(new EchoServerHandler());
}
});
//Binds server, waits for server to close, and releases resources
ChannelFuture f = b.bind().sync();
System.out.println(EchoServer.class.getName() + "started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws InterruptedException {
Server server = new Server(4456);
server.start();
}
}
public class ServerHandler extends SimpleChannelInboundHandler<Object>{
int unRecPingTimes = 0 ;
@Override
protected void channelRead0(ChannelHandlerContext arg0, Object arg1) throws Exception {
System.out.println("超时");
}
@Override
public void channelRead(ChannelHandlerContext arg0, Object arg1) throws Exception {
System.out.println("超时");
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.READER_IDLE) {
/*读超时*/
System.out.println("===服务端===(READER_IDLE 读超时)");
// 失败计数器次数大于等于3次的时候,关闭链接,等待client重连
if (unRecPingTimes>=3) {
ctx.channel().close();
} else {
unRecPingTimes++;
}
} else if (event.state() == IdleState.WRITER_IDLE) {
/*写超时*/
System.out.println("===服务端===(WRITER_IDLE 写超时)");
} else if (event.state() == IdleState.ALL_IDLE) {
/*总超时*/
System.out.println("===服务端===(ALL_IDLE 总超时)");
}
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Client active ");
}
}