Java Netty实现心跳机制过程解析
netty心跳机制示例,使用Netty实现心跳机制,使用netty4,IdleStateHandler实现。Netty心跳机制,netty心跳检测,netty,心跳
本文假设你已经了解了Netty的使用,或者至少写过netty的helloworld,知道了netty的基本使用。我们知道使用netty的时候,大多数的东西都与Handler有关,我们的业务逻辑基本都是在Handler中实现的。Netty中自带了一个IdleStateHandler可以用来实现心跳检测。
心跳检测的逻辑
本文中我们将要实现的心跳检测逻辑是这样的:服务端启动后,等待客户端连接,客户端连接之后,向服务端发送消息。如果客户端在“干活”那么服务端必定会收到数据,如果客户端“闲下来了”那么服务端就接收不到这个客户端的消息,既然客户端闲下来了,不干事,那么何必浪费连接资源呢?所以服务端检测到一定时间内客户端不活跃的时候,将客户端连接关闭。本文要实现的逻辑步骤为:
- 启动服务端,启动客户端
- 客户端向服务端发送"Iamalive",并sleep随机时间,用来模拟空闲。
- 服务端接收客户端消息,并返回"copythat",客户端空闲时计数+1.
- 服务端客户端继续通信
- 服务端检测客户端空闲太多,关闭连接。客户端发现连接关闭了,就退出了。
有了这个思路,我们先来编写服务端。
心跳检测服务端代码
publicclassHeartBeatServer{ intport; publicHeartBeatServer(intport){ this.port=port; } publicvoidstart(){ ServerBootstrapbootstrap=newServerBootstrap(); EventLoopGroupboss=newNioEventLoopGroup(); EventLoopGroupworker=newNioEventLoopGroup(); try{ bootstrap.group(boss,worker) .handler(newLoggingHandler(LogLevel.INFO)) .channel(NioServerSocketChannel.class) .childHandler(newHeartBeatInitializer()); ChannelFuturefuture=bootstrap.bind(port).sync(); future.channel().closeFuture().sync(); }catch(Exceptione){ e.printStackTrace(); }finally{ worker.shutdownGracefully(); boss.shutdownGracefully(); } } publicstaticvoidmain(String[]args)throwsException{ HeartBeatServerserver=newHeartBeatServer(8090); server.start(); } }
熟悉netty的同志,对于上面的模板一样的代码一定是在熟悉不过了。啥都不用看,只需要看childHandler(newHeartBeatInitializer())这一句。HeartBeatInitializer就是一个ChannelInitializer顾名思义,他就是在初始化channel的时做一些事情。我们所需要开发的业务逻辑Handler就是在这里添加的。其代码如下:
publicclassHeartBeatInitializerextendsChannelInitializer{ @Override protectedvoidinitChannel(Channelchannel)throwsException{ ChannelPipelinepipeline=channel.pipeline(); pipeline.addLast("decoder",newStringDecoder()); pipeline.addLast("encoder",newStringEncoder()); pipeline.addLast(newIdleStateHandler(2,2,2,TimeUnit.SECONDS)); pipeline.addLast(newHeartBeatHandler()); } }
代码很简单,我们先添加了StringDecoder,和StringEncoder。这两个其实就是编解码用的,下面的IdleStateHandler才是本次心跳的核心组件。我们可以看到IdleStateHandler的构造函数中接收了4个参数,其定义如下:
publicIdleStateHandler(longreaderIdleTime,longwriterIdleTime,longallIdleTime,TimeUnitunit);
三个空闲时间参数,以及时间参数的格式。我们的例子中设置的是2,2,2,意思就是客户端2秒没有读/写,这个超时时间就会被触发。超时事件触发就需要我们来处理了,这就是上的HeartBeatInitializer中最后一行的HeartBeatHandler所做的事情。代码如下:
publicclassHeartBeatHandlerextendsSimpleChannelInboundHandler{ intreadIdleTimes=0; @Override protectedvoidchannelRead0(ChannelHandlerContextctx,Strings)throwsException{ System.out.println("======>[server]messagereceived:"+s); if("Iamalive".equals(s)){ ctx.channel().writeAndFlush("copythat"); }else{ System.out.println("其他信息处理..."); } } @Override publicvoiduserEventTriggered(ChannelHandlerContextctx,Objectevt)throwsException{ IdleStateEventevent=(IdleStateEvent)evt; StringeventType=null; switch(event.state()){ caseREADER_IDLE: eventType="读空闲"; readIdleTimes++;//读空闲的计数加1 break; caseWRITER_IDLE: eventType="写空闲"; //不处理 break; caseALL_IDLE: eventType="读写空闲"; //不处理 break; } System.out.println(ctx.channel().remoteAddress()+"超时事件:"+eventType); if(readIdleTimes>3){ System.out.println("[server]读空闲超过3次,关闭连接"); ctx.channel().writeAndFlush("youareout"); ctx.channel().close(); } } @Override publicvoidchannelActive(ChannelHandlerContextctx)throwsException{ System.err.println("==="+ctx.channel().remoteAddress()+"isactive==="); } }
至此,我们的服务端写好了。
心跳检测客户端代码
netty的api设计使得编码的模式非常具有通用性,所以客户端代码和服务端的代码几乎一样:启动client端的代码几乎一样,也需要一个ChannelInitializer,也需要Handler。改动的地方很少,因此本文不对客户端代码进行详细解释。下面给出client端的完整代码:
publicclassHeartBeatClient{ intport; Channelchannel; Randomrandom; publicHeartBeatClient(intport){ this.port=port; random=newRandom(); } publicstaticvoidmain(String[]args)throwsException{ HeartBeatClientclient=newHeartBeatClient(8090); client.start(); } publicvoidstart(){ EventLoopGroupeventLoopGroup=newNioEventLoopGroup(); try{ Bootstrapbootstrap=newBootstrap(); bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class) .handler(newHeartBeatClientInitializer()); connect(bootstrap,port); Stringtext="Iamalive"; while(channel.isActive()){ sendMsg(text); } }catch(Exceptione){ //dosomething }finally{ eventLoopGroup.shutdownGracefully(); } } publicvoidconnect(Bootstrapbootstrap,intport)throwsException{ channel=bootstrap.connect("localhost",8090).sync().channel(); } publicvoidsendMsg(Stringtext)throwsException{ intnum=random.nextInt(10); Thread.sleep(num*1000); channel.writeAndFlush(text); } staticclassHeartBeatClientInitializerextendsChannelInitializer{ @Override protectedvoidinitChannel(Channelch)throwsException{ ChannelPipelinepipeline=ch.pipeline(); pipeline.addLast("decoder",newStringDecoder()); pipeline.addLast("encoder",newStringEncoder()); pipeline.addLast(newHeartBeatClientHandler()); } } staticclassHeartBeatClientHandlerextendsSimpleChannelInboundHandler { @Override protectedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg)throwsException{ System.out.println("clientreceived:"+msg); if(msg!=null&&msg.equals("youareout")){ System.out.println("serverclosedconnection,soclientwillclosetoo"); ctx.channel().closeFuture(); } } } }
运行代码
在上面的代码写好之后,我们先启动服务端,然后在启动客户端。运行日志如下:
server端:
===/127.0.0.1:57700isactive=== ======>[server]messagereceived:Iamalive ======>[server]messagereceived:Iamalive /127.0.0.1:57700超时事件:写空闲 /127.0.0.1:57700超时事件:读空闲 /127.0.0.1:57700超时事件:读写空闲 /127.0.0.1:57700超时事件:写空闲 /127.0.0.1:57700超时事件:读空闲 /127.0.0.1:57700超时事件:读写空闲 /127.0.0.1:57700超时事件:写空闲 ======>[server]messagereceived:Iamalive /127.0.0.1:57700超时事件:写空闲 /127.0.0.1:57700超时事件:读写空闲 /127.0.0.1:57700超时事件:读空闲 /127.0.0.1:57700超时事件:写空闲 /127.0.0.1:57700超时事件:读写空闲 /127.0.0.1:57700超时事件:读空闲 [server]读空闲超过3次,关闭连接
client端:
clientsentmsgandsleep2 clientreceived:copythat clientreceived:copythat clientsentmsgandsleep6 clientsentmsgandsleep6 clientreceived:copythat clientreceived:youareout serverclosedconnection,soclientwillclosetoo Processfinishedwithexitcode0
通过上面的运行日志,我们可以看到:
1.客户端在与服务器成功建立之后,发送了3次'Iamalive',服务端也回应了3次:'copythat'
2.由于客户端消极怠工,超时了多次,服务端关闭了链接。
3.客户端知道服务端抛弃自己之后,也关闭了连接,程序退出。
以上简单了演示了一下,netty的心跳机制,其实主要就是使用了IdleStateHandler。源码下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。