-
主要逻辑:
使用netty实现长连接,主要靠心跳来维持服务器端及客户端连接。
实现的逻辑主要是:
服务器端方面:
1, 服务器在网络空闲操作一定时间后,服务端失败心跳计数器加1。
2, 如果收到客户端的ping心跳包,则清零失败心跳计数器,如果连续n次未收到客户端的ping心跳包,则关闭链路,释放资源,等待客户端重连。
客户端方面:
1, 客户端网络空闲在一定时间内没有进行写操作时,则发送一个ping心跳包。
2, 如果服务器端未在发送下一个心跳包之前回复pong心跳应答包,则失败心跳计数器加1。
3, 如果客户端连续发送n(此处根据具体业务进行定义)次ping心跳包,服务器端均未回复pong心跳应答包,则客户端断开连接,间隔一定时间进行重连操作,直至连接服务器成功。
环境:netty5,tomcat7,jdk7,myeclipse
服务器端心跳处理类:
客户端心跳处理类:- public class HeartBeatReqHandler extends ChannelHandlerAdapter {
- private final Logger log=Logger.getLogger(HeartBeatReqHandler.class);
- //线程安全心跳失败计数器
- private AtomicInteger unRecPongTimes = new AtomicInteger(1);
- public void channelRead(ChannelHandlerContext ctx, Object msg)
- throws Exception {
- NettyMessageProto message = (NettyMessageProto)msg;
- //服务器端心跳回复
- if(message.getHeader() != null && message.getHeader().getType() == Constants.MSGTYPE_HEARTBEAT_RESPONSE){
- //如果服务器进行pong心跳回复,则清零失败心跳计数器
- unRecPongTimes = new AtomicInteger(1);
- log.debug("client receive server pong msg :---->"+message);
- }else{
- ctx.fireChannelRead(msg);
- }
- }
- /**
- * 事件触发器,该处用来处理客户端空闲超时,发送心跳维持连接。
- */
- public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
- if (evt instanceof IdleStateEvent) {
- IdleStateEvent event = (IdleStateEvent) evt;
- if (event.state() == IdleState.READER_IDLE) {
- /*读超时*/
- log.info("===客户端===(READER_IDLE 读超时)");
- } else if (event.state() == IdleState.WRITER_IDLE) {
- /*客户端写超时*/
- log.info("===客户端===(WRITER_IDLE 写超时)");
- unRecPongTimes.getAndIncrement();
- //服务端未进行pong心跳响应的次数小于3,则进行发送心跳,否则则断开连接。
- if(unRecPongTimes.intValue() < 3){
- //发送心跳,维持连接
- ctx.channel().writeAndFlush(buildHeartBeat()) ;
- log.info("客户端:发送心跳");
- }else{
- ctx.channel().close();
- }
- } else if (event.state() == IdleState.ALL_IDLE) {
- /*总超时*/
- log.info("===客户端===(ALL_IDLE 总超时)");
- }
- }
- }
- private NettyMessageProto buildHeartBeat(){
- HeaderProto header = HeaderProto.newBuilder().setType(Constants.MSGTYPE_HEARTBEAT_REQUEST).build();
- NettyMessageProto message = NettyMessageProto.newBuilder().setHeader(header).build();
- return message;
- }
- /**
- * 异常处理
- */
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception{
- ctx.fireExceptionCaught(cause);
- }
- }
- <pre code_snippet_id="2489110" snippet_file_name="blog_20170719_2_6056366" name="code" class="java"><pre code_snippet_id="2489110" snippet_file_name="blog_20170719_2_6056366"></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <link rel="stylesheet" href="http://static./public/res-min/markdown_views.css?v=1.0">
版权声明:本文为博主原创文章,未经博主允许不得转载。