Netty心跳简单Demo
前面简单地了解了一下IdleStateHandler,我们现在写一个简单的心跳demo:
1)服务器端每隔5秒检测服务器端的读超时,如果5秒没有接受到客户端的写请求,也就说服务器端5秒没有收到读事件,则视为一次超时
2)如果超时二次则说明连接处于不活跃的状态,关闭ServerChannel
3)客户端每隔4秒发送一些写请求,这个请求相当于一次心跳包,告之服务器端:客户端仍旧活着
我们开始先开始写服务器端的handler,继承ChannelInboundHandlerAdapter,我们先重写userEventTriggered方法,这个方法我们前面讲过,如果超时则会触发相应的超时事件
HeartBeatServerHandler.java
- package com.lyncc.netty.heartbeats;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.handler.timeout.IdleState;
- import io.netty.handler.timeout.IdleStateEvent;
- public class HeartBeatServerHandler extends ChannelInboundHandlerAdapter {
- private int loss_connect_time = 0;
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent event = (IdleStateEvent) evt;
- if (event.state() == IdleState.READER_IDLE) {
- loss_connect_time++;
- System.out.println("5 秒没有接收到客户端的信息了");
- if (loss_connect_time > 2) {
- System.out.println("关闭这个不活跃的channel");
- ctx.channel().close();
- }
- }
- } else {
- super.userEventTriggered(ctx, evt);
- }
- }
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- System.out.println("server channelRead..");
- System.out.println(ctx.channel().remoteAddress() + "->Server :" + msg.toString());
- }
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
- cause.printStackTrace();
- ctx.close();
- }
- }
再写一下服务器端,我们要注意的是,我们要在channelPipeline中加入IdleStateHandler,我们在handler中提示的是5秒读,所以我们配置的是:
这样就可以每隔5秒检测一下服务端的读超时。完整代码清单如下:
- package com.lyncc.netty.heartbeats;
- import io.netty.bootstrap.ServerBootstrap;
- 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.SocketChannel;
- 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.logging.LogLevel;
- import io.netty.handler.logging.LoggingHandler;
- import io.netty.handler.timeout.IdleStateHandler;
- import java.net.InetSocketAddress;
- import java.util.concurrent.TimeUnit;
- public class HeartBeatServer {
- private int port;
- public HeartBeatServer(int port) {
- this.port = port;
- }
- public void start(){
- EventLoopGroup bossGroup = new NioEventLoopGroup(1);
- EventLoopGroup workerGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).localAddress(new InetSocketAddress(port))
- .childHandler(new ChannelInitializer<SocketChannel>() {
- protected void initChannel(SocketChannel ch) throws Exception {
- ch.pipeline().addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
- ch.pipeline().addLast("decoder", new StringDecoder());
- ch.pipeline().addLast("encoder", new StringEncoder());
- ch.pipeline().addLast(new HeartBeatServerHandler());
- };
- }).option(ChannelOption.SO_BACKLOG, 128)
- .childOption(ChannelOption.SO_KEEPALIVE, true);
- // 绑定端口,开始接收进来的连接
- ChannelFuture future = sbs.bind(port).sync();
- System.out.println("Server start listen at " + port );
- future.channel().closeFuture().sync();
- } catch (Exception e) {
- bossGroup.shutdownGracefully();
- workerGroup.shutdownGracefully();
- }
- }
- public static void main(String[] args) throws Exception {
- int port;
- if (args.length > 0) {
- port = Integer.parseInt(args[0]);
- } else {
- port = 8080;
- }
- new HeartBeatServer(port).start();
- }
- }
HeartBeatClientHandler.java方法也重写userEventTriggered方法,因为客户端没有任何写的情况,所以我们可以每次都能进行写超时:
也就说这个方法每隔4秒都能触发:
红色边框代码在客户端没有写事件的时候,一超时就会触发写请求:
完整代码如下:
HeartBeatClientHandler.java
- package com.lyncc.netty.heartbeats;
- import java.util.Date;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.channel.ChannelInboundHandlerAdapter;
- import io.netty.handler.timeout.IdleState;
- import io.netty.handler.timeout.IdleStateEvent;
- import io.netty.util.CharsetUtil;
- import io.netty.util.ReferenceCountUtil;
- public class HeartBeatClientHandler extends ChannelInboundHandlerAdapter {
- private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
- CharsetUtil.UTF_8));
- private static final int TRY_TIMES = 3;
- private int currentTime = 0;
- @Override
- public void channelActive(ChannelHandlerContext ctx) throws Exception {
- System.out.println("激活时间是:"+new Date());
- System.out.println("HeartBeatClientHandler channelActive");
- ctx.fireChannelActive();
- }
- @Override
- public void channelInactive(ChannelHandlerContext ctx) throws Exception {
- System.out.println("停止时间是:"+new Date());
- System.out.println("HeartBeatClientHandler channelInactive");
- }
- @Override
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- System.out.println("循环触发时间:"+new Date());
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent event = (IdleStateEvent) evt;
- if (event.state() == IdleState.WRITER_IDLE) {
- if(currentTime <= TRY_TIMES){
- System.out.println("currentTime:"+currentTime);
- currentTime++;
- ctx.channel().writeAndFlush(HEARTBEAT_SEQUENCE.duplicate());
- }
- }
- }
- }
- @Override
- public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- String message = (String) msg;
- System.out.println(message);
- if (message.equals("Heartbeat")) {
- ctx.write("has read message from server");
- ctx.flush();
- }
- ReferenceCountUtil.release(msg);
- }
- }
HeartBeatsClient.java
客户端代码也要加入IdleStateHandler这个handler,注意的是,我们要注意的是写超时,所以要设置写超时的时间,因为服务器端是5秒检测读超时,所以客户端必须在5秒内发送一次心跳,告之服务端,所以我们设置4秒:
完整代码如下:
- package com.lyncc.netty.heartbeats;
- import java.util.concurrent.TimeUnit;
- import io.netty.bootstrap.Bootstrap;
- import io.netty.channel.ChannelFuture;
- import io.netty.channel.ChannelInitializer;
- import io.netty.channel.ChannelOption;
- import io.netty.channel.ChannelPipeline;
- import io.netty.channel.EventLoopGroup;
- import io.netty.channel.nio.NioEventLoopGroup;
- import io.netty.channel.socket.SocketChannel;
- import io.netty.channel.socket.nio.NioSocketChannel;
- import io.netty.handler.codec.string.StringDecoder;
- import io.netty.handler.codec.string.StringEncoder;
- import io.netty.handler.logging.LogLevel;
- import io.netty.handler.logging.LoggingHandler;
- import io.netty.handler.timeout.IdleStateHandler;
- public class HeartBeatsClient {
- public void connect(int port, String host) throws Exception {
- // Configure the client.
- EventLoopGroup group = new NioEventLoopGroup();
- try {
- Bootstrap b = new Bootstrap();
- b.group(group)
- .channel(NioSocketChannel.class)
- .option(ChannelOption.TCP_NODELAY, true)
- .handler(new LoggingHandler(LogLevel.INFO))
- .handler(new ChannelInitializer<SocketChannel>() {
- @Override
- public void initChannel(SocketChannel ch) throws Exception {
- ChannelPipeline p = ch.pipeline();
- p.addLast("ping", new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS));
- p.addLast("decoder", new StringDecoder());
- p.addLast("encoder", new StringEncoder());
- p.addLast(new HeartBeatClientHandler());
- }
- });
- ChannelFuture future = b.connect(host, port).sync();
- future.channel().closeFuture().sync();
- } finally {
- group.shutdownGracefully();
- }
- }
- /**
- * @param args
- * @throws Exception
- */
- public static void main(String[] args) throws Exception {
- int port = 8080;
- if (args != null && args.length > 0) {
- try {
- port = Integer.valueOf(args[0]);
- } catch (NumberFormatException e) {
- // 采用默认值
- }
- }
- new HeartBeatsClient().connect(port, "127.0.0.1");
- }
- }
我们先启动服务器端:
再启动客户端:
此时客户端还存活着,我们看看服务器端的输出:
我们再看看客户端的输出:
inactive的事件触发了,且客户端自动停止了~
Netty心跳简单Demo的更多相关文章
- Netty的简单Demo
这个demo是通过网上下载: 使用maven构建的: 项目结构: pom.xml: <dependencies> <dependency> <groupId>io. ...
- 连接管理 与 Netty 心跳机制
一.前言 踏踏实实,动手去做,talk is cheap, show me the code.先介绍下基础知识,然后做个心跳机制的Demo. 二.连接 长连接:在整个通讯过程,客户端和服务端只用一个S ...
- NETTY 心跳机制
最近工作比较忙,但闲暇之余还是看了阿里的冯家春(fengjiachun)的github上的开源代码Jupiter,写的RPC框架让我感叹人外有人,废话不多说,下面的代码全部截取自Jupiter,写了一 ...
- 设计模式之单例模式的简单demo
/* * 设计模式之单例模式的简单demo */ class Single { /* * 创建一个本类对象. * 和get/set方法思想一样,类不能直接调用对象 * 所以用private限制权限 * ...
- Spring的简单demo
---------------------------------------- 开发一个Spring的简单Demo,具体的步骤如下: 1.构造一个maven项目 2.在maven项目的pom.xml ...
- 使用Spring缓存的简单Demo
使用Spring缓存的简单Demo 1. 首先创建Maven工程,在Pom中配置 <dependency> <groupId>org.springframework</g ...
- Managed DirectX中的DirectShow应用(简单Demo及源码)
阅读目录 介绍 准备工作 环境搭建 简单Demo 显示效果 其他 Demo下载 介绍 DirectX是Microsoft开发的基于Windows平台的一组API,它是为高速的实时动画渲染.交互式音乐和 ...
- angular实现了一个简单demo,angular-weibo-favorites
前面必须说一段 帮客户做了一个过渡期的项目,唯一的要求就是速度,我只是会点儿基础的php,于是就用tp帮客户做了这个项目.最近和客户架构沟通,后期想把项目重新做一下,就用现在最流行的技术,暂时想的使用 ...
- Solr配置与简单Demo[转]
Solr配置与简单Demo 简介: solr是基于Lucene Java搜索库的企业级全文搜索引擎,目前是apache的一个项目.它的官方网址在http://lucene.apache.org/sol ...
随机推荐
- nginx初步尝试
导师要我学习下nginx,弄个简单的负载均衡出来,具体就是请求发送到nginx上,然后nginx将请求转发到后面的两个jetty应用上,这两个应用的代码是一样的,只是监听的端口不同,由于是简单尝试,因 ...
- linux下vi命令(转)
进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filename :打开文件,并将光标置于第n行首 vi + filename :打开文件,并将光标置于最后 ...
- java大文件断点续传
java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路:1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接操 ...
- NOI2001 食物链【扩展域并查集】*
NOI2001 食物链 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的 ...
- 实现一个 WPF 版本的 ConnectedAnimation
Windows 10 的创造者更新为开发者们带来了 Connected Animation 连接动画,这也是 Fluent Design System 的一部分.它的视觉引导性很强,用户能够在它的帮助 ...
- flask第十二篇——自定义url转换器【2】
继续昨天的话题,今天我们来写一个手机号的转换器,方便大家理解 我们在`BaseConverter`源码里看到好多这种正则表达式: 正则表达式的目的就是规范匹配的规则,现在我们写一个简单的匹配手机号的正 ...
- 让Apache支持URL重写
第一步: 添加.htaccess文件 Rewrite 规则 <IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{REQUEST_ ...
- LeetCode 760. Find Anagram Mappings
原题链接在这里:https://leetcode.com/problems/find-anagram-mappings/description/ 题目: Given two lists Aand B, ...
- jest js 测试框架-简单方便人性化
1. 安装 yarn global add jest-cli or npm install -g jest-cli 备注:可以安装为依赖不用全局安装 2. 项目代码 a. 项目初始化 yarn ini ...
- 在vue中无论使用router-link 还是 @click事件,发现都没法从列表页点击跳转到内容页去
在vue中如论使用router-link 还是 @click事件,发现都没法从列表页点击跳转到内容页去,以前都是可以的,想着唯一不同的场景就是因为运用了scroll组件(https://ustbhua ...