前面简单地了解了一下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. 每天一个linux命令:【转载】cat命令

    cat命令的用途是连接文件或标准输入并打印.这个命令常用来显示文件内容,或者将几个文件连接起来显示,或者从标准输入读取内容并显示,它常与重定向符号配合使用. 1.命令格式: cat [选项] [文件] ...

  2. BZOJ2933 [Poi1999]地图【区间DP】

    Description 一个人口统计办公室要绘制一张地图.由于技术的原因只能使用少量的颜色.两个有相同或相近人口的区域在地图应用相同的颜色.例如一种颜色k,则A(k) 是相应的数,则有: 在用颜色k的 ...

  3. BZOJ5297 CQOI2018 社交网络 【矩阵树定理Matrix-Tree】

    BZOJ5297 CQOI2018 社交网络 Description 当今社会,在社交网络上看朋友的消息已经成为许多人生活的一部分.通常,一个用户在社交网络上发布一条消息(例如微博.状态.Tweet等 ...

  4. 《DSP using MATLAB》示例Example 8.29

    %% ------------------------------------------------------------------------ %% Output Info about thi ...

  5. 《DSP using MATLAB》示例Example 8.19

    代码: %% ------------------------------------------------------------------------ %% Output Info about ...

  6. 在Eclipse中导入dtd和xsd文件,使XML自动提示

    DTD 类型约束文件    1. Window->Preferences->XML->XML Catalog->User Specified Entries窗口中,选择Add ...

  7. odoo10 修改产品单价的小数点位数

    odoo10 修改产品单价的小数点位数 由于产品价格原因,单价需要保留小数点后 5 位,所以需要修改单价的小数点位数. 开启开发模式 找到数据库编辑 找到小数点精度 修改产品的小数点位数

  8. 【转】我的第一个Python小程序

    原文网址:http://blog.csdn.net/randyqiu/article/details/4484089 人的每个第一次都有点特别的意义,所以下面这个小程序我把他记录下来做个纪念. 因为要 ...

  9. ffmpeg从USB摄像头采集一张原始图片(转)

    本文讲解使用ffmpeg从USB摄像头中采集一帧数据并写入文件保存,测试平台使用全志A20平台,其他平台修改交叉工具链即可移植.开发环境使用eclipse+CDT.交叉工具链使用arm-Linux-g ...

  10. 手动下载阿里云Nexus上的Jar包

    手动下载阿里云Nexus上的Jar包 1.1 在任意目录下创建一个文件夹,创建一个pom.xml文件,一个bat批处理脚本,如图: 1.2 DownLoad.bat文件中的内容: call mvn - ...