NettyServer:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
// 创建两个线程组
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO)) //在 bossGroup 增加一个日志处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
/**
* 加入一个 netty 提供的 idlestateHandler
* IdlestateHandler 是 netty 提供的处理空闲状态的处理器
* readerIdleTime: 表示多长时间没有读, 就会发送一个心跳检测包 检测是否是连接的状态
* writerIdleTime: 表示多长时间没有写操作了,就会发送一个心跳检测包检测是否连接
* allIdleTime: 表示多长时间没有读写操作了,就会发送一个心跳检测包检测是否连接
* 当 idleStateEvent 触发后,就会传递给管道的下一个 handler 去处理,通过调用(触发) 下一个 handler的 userEventTriggered,在
* 该方法中去处理 idleStateEvent(读空闲, 写空闲,读写空闲)
*/
pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
// 加入一个空闲检测进一步处理的 handler(自定义)
pipeline.addLast(new NettyServerHandler());
}
});
ChannelFuture channelFuture = bootstrap.bind(9527).sync();
channelFuture.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerHandler:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
/**
* @param ctx 上下文
* @param evt 事件
* @throws Exception
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
// 将 evt 向下转型 IdleStateEvent
IdleStateEvent event = (IdleStateEvent) evt;
String eventType = null;
switch (event.state()){
case READER_IDLE:
eventType = "读空闲";
break;
case WRITER_IDLE:
eventType = "写空闲";
break;
case ALL_IDLE:
eventType = "读写空闲";
break;
}
System.out.println(ctx.channel().remoteAddress() + "-- 超时事件 --" + eventType);
System.out.println("服务器做相应处理..");
// 如果发生空闲,我们关闭通道
ctx.channel().close();
}
}
}