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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。