前面简单地了解了一下IdleStateHandler,我们现在写一个简单的心跳demo:

1)服务器端每隔5秒检测服务器端的读超时,如果5秒没有接受到客户端的写请求,也就说服务器端5秒没有收到读事件,则视为一次超时

2)如果超时二次则说明连接处于不活跃的状态,关闭ServerChannel

3)客户端每隔4秒发送一些写请求,这个请求相当于一次心跳包,告之服务器端:客户端仍旧活着

我们开始先开始写服务器端的handler,继承ChannelInboundHandlerAdapter,我们先重写userEventTriggered方法,这个方法我们前面讲过,如果超时则会触发相应的超时事件

HeartBeatServerHandler.java

  1. package com.lyncc.netty.heartbeats;
  2. import io.netty.channel.ChannelHandlerContext;
  3. import io.netty.channel.ChannelInboundHandlerAdapter;
  4. import io.netty.handler.timeout.IdleState;
  5. import io.netty.handler.timeout.IdleStateEvent;
  6. public class HeartBeatServerHandler extends ChannelInboundHandlerAdapter {
  7. private int loss_connect_time = 0;
  8. @Override
  9. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  10. if (evt instanceof IdleStateEvent) {
  11. IdleStateEvent event = (IdleStateEvent) evt;
  12. if (event.state() == IdleState.READER_IDLE) {
  13. loss_connect_time++;
  14. System.out.println("5 秒没有接收到客户端的信息了");
  15. if (loss_connect_time > 2) {
  16. System.out.println("关闭这个不活跃的channel");
  17. ctx.channel().close();
  18. }
  19. }
  20. } else {
  21. super.userEventTriggered(ctx, evt);
  22. }
  23. }
  24. @Override
  25. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  26. System.out.println("server channelRead..");
  27. System.out.println(ctx.channel().remoteAddress() + "->Server :" + msg.toString());
  28. }
  29. @Override
  30. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  31. cause.printStackTrace();
  32. ctx.close();
  33. }
  34. }

再写一下服务器端,我们要注意的是,我们要在channelPipeline中加入IdleStateHandler,我们在handler中提示的是5秒读,所以我们配置的是:


这样就可以每隔5秒检测一下服务端的读超时。完整代码清单如下:

  1. package com.lyncc.netty.heartbeats;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioServerSocketChannel;
  10. import io.netty.handler.codec.string.StringDecoder;
  11. import io.netty.handler.codec.string.StringEncoder;
  12. import io.netty.handler.logging.LogLevel;
  13. import io.netty.handler.logging.LoggingHandler;
  14. import io.netty.handler.timeout.IdleStateHandler;
  15. import java.net.InetSocketAddress;
  16. import java.util.concurrent.TimeUnit;
  17. public class HeartBeatServer {
  18. private int port;
  19. public HeartBeatServer(int port) {
  20. this.port = port;
  21. }
  22. public void start(){
  23. EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  24. EventLoopGroup workerGroup = new NioEventLoopGroup();
  25. try {
  26. ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).localAddress(new InetSocketAddress(port))
  27. .childHandler(new ChannelInitializer<SocketChannel>() {
  28. protected void initChannel(SocketChannel ch) throws Exception {
  29. ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
  30. ch.pipeline().addLast("decoder", new StringDecoder());
  31. ch.pipeline().addLast("encoder", new StringEncoder());
  32. ch.pipeline().addLast(new HeartBeatServerHandler());
  33. };
  34. }).option(ChannelOption.SO_BACKLOG, 128)
  35. .childOption(ChannelOption.SO_KEEPALIVE, true);
  36. // 绑定端口,开始接收进来的连接
  37. ChannelFuture future = sbs.bind(port).sync();
  38. System.out.println("Server start listen at " + port );
  39. future.channel().closeFuture().sync();
  40. } catch (Exception e) {
  41. bossGroup.shutdownGracefully();
  42. workerGroup.shutdownGracefully();
  43. }
  44. }
  45. public static void main(String[] args) throws Exception {
  46. int port;
  47. if (args.length > 0) {
  48. port = Integer.parseInt(args[0]);
  49. } else {
  50. port = 8080;
  51. }
  52. new HeartBeatServer(port).start();
  53. }
  54. }

HeartBeatClientHandler.java方法也重写userEventTriggered方法,因为客户端没有任何写的情况,所以我们可以每次都能进行写超时:

也就说这个方法每隔4秒都能触发:

红色边框代码在客户端没有写事件的时候,一超时就会触发写请求:

完整代码如下:

HeartBeatClientHandler.java

  1. package com.lyncc.netty.heartbeats;
  2. import java.util.Date;
  3. import io.netty.buffer.ByteBuf;
  4. import io.netty.buffer.Unpooled;
  5. import io.netty.channel.ChannelHandlerContext;
  6. import io.netty.channel.ChannelInboundHandlerAdapter;
  7. import io.netty.handler.timeout.IdleState;
  8. import io.netty.handler.timeout.IdleStateEvent;
  9. import io.netty.util.CharsetUtil;
  10. import io.netty.util.ReferenceCountUtil;
  11. public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {
  12. private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
  13. CharsetUtil.UTF_8));
  14. private static final int TRY_TIMES = 3;
  15. private int currentTime = 0;
  16. @Override
  17. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  18. System.out.println("激活时间是:"+new Date());
  19. System.out.println("HeartBeatClientHandler channelActive");
  20. ctx.fireChannelActive();
  21. }
  22. @Override
  23. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  24. System.out.println("停止时间是:"+new Date());
  25. System.out.println("HeartBeatClientHandler channelInactive");
  26. }
  27. @Override
  28. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  29. System.out.println("循环触发时间:"+new Date());
  30. if (evt instanceof IdleStateEvent) {
  31. IdleStateEvent event = (IdleStateEvent) evt;
  32. if (event.state() == IdleState.WRITER_IDLE) {
  33. if(currentTime <= TRY_TIMES){
  34. System.out.println("currentTime:"+currentTime);
  35. currentTime++;
  36. ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());
  37. }
  38. }
  39. }
  40. }
  41. @Override
  42. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  43. String message = (String) msg;
  44. System.out.println(message);
  45. if (message.equals("Heartbeat")) {
  46. ctx.write("has read message from server");
  47. ctx.flush();
  48. }
  49. ReferenceCountUtil.release(msg);
  50. }
  51. }

HeartBeatsClient.java

客户端代码也要加入IdleStateHandler这个handler,注意的是,我们要注意的是写超时,所以要设置写超时的时间,因为服务器端是5秒检测读超时,所以客户端必须在5秒内发送一次心跳,告之服务端,所以我们设置4秒:

完整代码如下:

  1. package com.lyncc.netty.heartbeats;
  2. import java.util.concurrent.TimeUnit;
  3. import io.netty.bootstrap.Bootstrap;
  4. import io.netty.channel.ChannelFuture;
  5. import io.netty.channel.ChannelInitializer;
  6. import io.netty.channel.ChannelOption;
  7. import io.netty.channel.ChannelPipeline;
  8. import io.netty.channel.EventLoopGroup;
  9. import io.netty.channel.nio.NioEventLoopGroup;
  10. import io.netty.channel.socket.SocketChannel;
  11. import io.netty.channel.socket.nio.NioSocketChannel;
  12. import io.netty.handler.codec.string.StringDecoder;
  13. import io.netty.handler.codec.string.StringEncoder;
  14. import io.netty.handler.logging.LogLevel;
  15. import io.netty.handler.logging.LoggingHandler;
  16. import io.netty.handler.timeout.IdleStateHandler;
  17. public class HeartBeatsClient {
  18. public void connect(int port, String host) throws Exception {
  19. // Configure the client.
  20. EventLoopGroup group = new NioEventLoopGroup();
  21. try {
  22. Bootstrap b = new Bootstrap();
  23. b.group(group)
  24. .channel(NioSocketChannel.class)
  25. .option(ChannelOption.TCP_NODELAY, true)
  26. .handler(new LoggingHandler(LogLevel.INFO))
  27. .handler(new ChannelInitializer<SocketChannel>() {
  28. @Override
  29. public void initChannel(SocketChannel ch) throws Exception {
  30. ChannelPipeline p = ch.pipeline();
  31. p.addLast("ping", new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));
  32. p.addLast("decoder", new StringDecoder());
  33. p.addLast("encoder", new StringEncoder());
  34. p.addLast(new HeartBeatClientHandler());
  35. }
  36. });
  37. ChannelFuture future = b.connect(host, port).sync();
  38. future.channel().closeFuture().sync();
  39. } finally {
  40. group.shutdownGracefully();
  41. }
  42. }
  43. /**
  44. * @param args
  45. * @throws Exception
  46. */
  47. public static void main(String[] args) throws Exception {
  48. int port = 8080;
  49. if (args != null && args.length > 0) {
  50. try {
  51. port = Integer.valueOf(args[0]);
  52. } catch (NumberFormatException e) {
  53. // 采用默认值
  54. }
  55. }
  56. new HeartBeatsClient().connect(port, "127.0.0.1");
  57. }
  58. }

我们先启动服务器端:

再启动客户端:

此时客户端还存活着,我们看看服务器端的输出:

我们再看看客户端的输出:

inactive的事件触发了,且客户端自动停止了~

Netty心跳简单Demo的更多相关文章

  1. Netty的简单Demo

    这个demo是通过网上下载: 使用maven构建的: 项目结构: pom.xml: <dependencies> <dependency> <groupId>io. ...

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

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

  3. NETTY 心跳机制

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

  4. 设计模式之单例模式的简单demo

    /* * 设计模式之单例模式的简单demo */ class Single { /* * 创建一个本类对象. * 和get/set方法思想一样,类不能直接调用对象 * 所以用private限制权限 * ...

  5. Spring的简单demo

    ---------------------------------------- 开发一个Spring的简单Demo,具体的步骤如下: 1.构造一个maven项目 2.在maven项目的pom.xml ...

  6. 使用Spring缓存的简单Demo

    使用Spring缓存的简单Demo 1. 首先创建Maven工程,在Pom中配置 <dependency> <groupId>org.springframework</g ...

  7. Managed DirectX中的DirectShow应用(简单Demo及源码)

    阅读目录 介绍 准备工作 环境搭建 简单Demo 显示效果 其他 Demo下载 介绍 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染.交互式音乐和 ...

  8. angular实现了一个简单demo,angular-weibo-favorites

    前面必须说一段 帮客户做了一个过渡期的项目,唯一的要求就是速度,我只是会点儿基础的php,于是就用tp帮客户做了这个项目.最近和客户架构沟通,后期想把项目重新做一下,就用现在最流行的技术,暂时想的使用 ...

  9. Solr配置与简单Demo[转]

    Solr配置与简单Demo 简介: solr是基于Lucene Java搜索库的企业级全文搜索引擎,目前是apache的一个项目.它的官方网址在http://lucene.apache.org/sol ...

随机推荐

  1. wait() ,notify() ,notifyAll(),synchronized 和同步方法锁,对象锁的联系,关系,区别;

    一直不明白一个问题,因为在书上关于生产者和消费者的例子里看到一段这样的代码,估计很多人都和我一样迷惑 public synchronized void set(String name, String ...

  2. Working out

    Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the ...

  3. 实用且堪称神器的Chrome插件推荐

    前言 相信很多人都在使用 Chrome 浏览器,其流畅的浏览体验得到了不少用户的偏爱,但流畅只是一方面, Chrome 最大的优势还是其支持众多强大好用的扩展程序(Extensions).最近为了更好 ...

  4. Cassandra spring data 试用

    1. maven  依赖 <dependency> <groupId>org.springframework.data</groupId> <artifact ...

  5. java nio和bio

    理解同步/异步,阻塞/非阻塞:https://juejin.im/entry/598da7d16fb9a03c42431ed3 2:http://qindongliang.iteye.com/blog ...

  6. ecmall2.3.0 前后台样式等无效,导致前台页面显示不正常问题解决

    问题一:按照安装手册安装及数据初始化后,前后台中文均出现乱码 解决方法:在upload/index.php 和 upload/admin/index.php 头上加上header("Cont ...

  7. JLink RTT Client代替printf(IAR测试OK)

    1.打开J-Link安装目录,确保SEGGER目录中有J-Link RTT Client,没有的话必须安装4.9以上版本: 2.打开SEGGER目录下软件SEGGER目录,硬件版本Hardware是8 ...

  8. 系统管理员都要知道的 30 个 Linux 系统监控工具

    1. top - 进程活动监控命令 top 命令会显示 Linux 的进程.它提供了一个运行中系统的实时动态视图,即实际的进程活动.默认情况下,它显示在服务器上运行的 CPU 占用率最高的任务,并且每 ...

  9. LINK : warning LNK4098: 默认库“LIBCMTD”与其他库的使用冲突;请使用 /NODEFAULTLIB:library

    LINK : warning LNK4098: 默认库“LIBCMTD”与其他库的使用冲突:请使用 /NODEFAULTLIB:library 转自:http://blog.csdn.net/pgms ...

  10. Firewalld防火墙与ICMP攻击

    原文地址:http://www.excelib.com/article/293/show 提到ICMP大家应该都很熟悉,可能有人会说:不就是ping吗?但是说到ICMP攻击以及相关防御措施可能就有的人 ...