zoukankan      html  css  js  c++  java
  • 基于MINA实现server端心跳检测(KeepAliveFilter)

    MINA自带了对心跳协议的支持,可以对心跳做出细致的配置,本文在次基础上实现了server端对client端的心跳检测。

    在开始之前先简单介绍下keepAlive的机制:

    首先,需要搞清楚TCP keepalive是干什么用的。从名字理解就能够知道,keepalive就是用来检测一个tcp connection是否还连接正常。当一个tcp connection建立好之后,如果双方都不发送数据的话,tcp协议本身是不会发送其它的任何数据的,也就是说,在一个idle的connection上,两个socket之间不产生任何的数据交换。从另一个方面讲,当一个connection建立之后,链接双方可以长时间的不发送任何数据,比如几天,几星期甚至几个月,但该connection仍然存在。

    所以,这就可能出现一个问题。举例来说,server和client建立了一个connection,server负责接收client的request。当connection建立好之后,client由于某种原因机器停机了。但server端并不知道,所以server就会一直监听着这个connection,但其实这个connection已经失效了。

    keepalive就是为这样的场景准备的。当把一个socket设置成了keepalive,那么这个socket空闲一段时间后,它就会向对方发送数据来确认对方仍然存在。放在上面的例子中,如果client停机了,那么server所发送的keepalive数据就不会有response,这样server就能够确认client完蛋了(至少从表面上看是这样)。

     

    具体的源代码如下:

     

    Server.java

    1. import java.io.IOException;  
    2. import java.net.InetSocketAddress;  
    3. import java.nio.charset.Charset;  
    4.   
    5. import org.apache.mina.core.service.IoAcceptor;  
    6. import org.apache.mina.core.session.IdleStatus;  
    7. import org.apache.mina.core.session.IoSession;  
    8. import org.apache.mina.filter.codec.ProtocolCodecFilter;  
    9. import org.apache.mina.filter.keepalive.KeepAliveFilter;  
    10. import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;  
    11. import org.apache.mina.filter.logging.LoggingFilter;  
    12. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;  
    13. import org.slf4j.Logger;  
    14. import org.slf4j.LoggerFactory;  
    15.   
    16. public class Server {  
    17.   
    18.     private static final int PORT = 9123;  
    19.     /** 30秒后超时 */  
    20.     private static final int IDELTIMEOUT = 30;  
    21.     /** 15秒发送一次心跳包 */  
    22.     private static final int HEARTBEATRATE = 15;  
    23.     /** 心跳包内容 */  
    24.     private static final String HEARTBEATREQUEST = "0x11";  
    25.     private static final String HEARTBEATRESPONSE = "0x12";  
    26.     private static final Logger LOG = LoggerFactory.getLogger(Server.class);  
    27.   
    28.     public static void main(String[] args) throws IOException {  
    29.         IoAcceptor acceptor = new NioSocketAcceptor();  
    30.         acceptor.getSessionConfig().setReadBufferSize(1024);  
    31.         acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE,  
    32.                 IDELTIMEOUT);  
    33.           
    34.         acceptor.getFilterChain().addLast("logger"new LoggingFilter());  
    35.         acceptor.getFilterChain().addLast(  
    36.                 "codec",  
    37.                 new ProtocolCodecFilter(new TextLineCodecFactory()));  
    38.   
    39.         KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();  
    40.         //下面注释掉的是自定义Handler方式  
    41. //      KeepAliveRequestTimeoutHandler heartBeatHandler = new   
    42. //                              KeepAliveRequestTimeoutHandlerImpl();  
    43. //      KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,  
    44. //              IdleStatus.BOTH_IDLE, heartBeatHandler);  
    45.           
    46.         KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,  
    47.                 IdleStatus.BOTH_IDLE);  
    48.   
    49.         //设置是否forward到下一个filter  
    50.         heartBeat.setForwardEvent(true);  
    51.         //设置心跳频率  
    52.         heartBeat.setRequestInterval(HEARTBEATRATE);  
    53.   
    54.         acceptor.getFilterChain().addLast("heartbeat", heartBeat);  
    55.   
    56.         acceptor.setHandler(new MyIoHandler());  
    57.         acceptor.bind(new InetSocketAddress(PORT));  
    58.         System.out.println("Server started on port: " + PORT);  
    59.     }  
    60.   
    61.     /** 
    62.      * @ClassName KeepAliveMessageFactoryImpl 
    63.      * @Description 内部类,实现KeepAliveMessageFactory(心跳工厂) 
    64.      * @author cruise 
    65.      * 
    66.      */  
    67.     private static class KeepAliveMessageFactoryImpl implements  
    68.             KeepAliveMessageFactory {  
    69.   
    70.         @Override  
    71.         public boolean isRequest(IoSession session, Object message) {  
    72.             LOG.info("请求心跳包信息: " + message);  
    73.             if (message.equals(HEARTBEATREQUEST))  
    74.                 return true;  
    75.             return false;  
    76.         }  
    77.   
    78.         @Override  
    79.         public boolean isResponse(IoSession session, Object message) {  
    80. //          LOG.info("响应心跳包信息: " + message);  
    81. //          if(message.equals(HEARTBEATRESPONSE))  
    82. //              return true;  
    83.             return false;  
    84.         }  
    85.   
    86.         @Override  
    87.         public Object getRequest(IoSession session) {  
    88.             LOG.info("请求预设信息: " + HEARTBEATREQUEST);  
    89.             /** 返回预设语句 */  
    90.             return HEARTBEATREQUEST;  
    91.         }  
    92.   
    93.         @Override  
    94.         public Object getResponse(IoSession session, Object request) {  
    95.             LOG.info("响应预设信息: " + HEARTBEATRESPONSE);  
    96.             /** 返回预设语句 */  
    97.             return HEARTBEATRESPONSE;  
    98. //          return null;  
    99.         }  
    100.   
    101.     }  
    102.       
    103.     /** 
    104.      * 对应上面的注释 
    105.      * KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE,heartBeatHandler) 
    106.      * 心跳超时处理 
    107.      * KeepAliveFilter 在没有收到心跳消息的响应时,会报告给的KeepAliveRequestTimeoutHandler。 
    108.      * 默认的处理是 KeepAliveRequestTimeoutHandler.CLOSE 
    109.      * (即如果不给handler参数,则会使用默认的从而Close这个Session) 
    110.      * @author cruise 
    111.      * 
    112.      */  
    113.   
    114. //  private static class KeepAliveRequestTimeoutHandlerImpl implements  
    115. //          KeepAliveRequestTimeoutHandler {  
    116. //  
    117. //    
    118. //      @Override  
    119. //      public void keepAliveRequestTimedOut(KeepAliveFilter filter,  
    120. //              IoSession session) throws Exception {  
    121. //          Server.LOG.info("心跳超时!");  
    122. //      }  
    123. //  
    124. //  }  
    125. }  


    MyIoHandler.java

    1. import org.apache.mina.core.service.IoHandlerAdapter;  
    2. import org.apache.mina.core.session.IoSession;  
    3. import org.slf4j.Logger;  
    4. import org.slf4j.LoggerFactory;  
    5.   
    6.   
    7. public class MyIoHandler extends IoHandlerAdapter{  
    8.     private final static Logger log = LoggerFactory  
    9.             .getLogger(MyIoHandler.class);  
    10.   
    11.     @Override  
    12.     public void sessionOpened(IoSession session) throws Exception {  
    13.           
    14.     }  
    15.   
    16.     @Override  
    17.     public void sessionClosed(IoSession session) throws Exception {  
    18.           
    19.     }  
    20.   
    21.     @Override  
    22.     public void messageReceived(IoSession session, Object message)  
    23.             throws Exception {  
    24.         String ip = session.getRemoteAddress().toString();  
    25.         log.info("===> Message From " + ip + " : " + message);         
    26.     }  
    27.       
    28.       
    29.   
    30. }  


    启动Server后,运行telnet客户端连接到Server端,便可以测试心跳;

    测试结果如下图:

    更多0

  • 相关阅读:
    Java并发编程:线程池的使用
    java动态代理实现与原理详细分析
    Springmvc 横向源码原理解析(原创)
    spring事物配置,声明式事务管理和基于@Transactional注解的使用
    Spring IoC的原理为什么是反射而不是new
    Mybatis源码分析(原创)
    Springboot中做定时任务 和 Springboot API 分页
    python程序入门 基础教程
    本地的jar包添加到maven库中 jdbc举例
    基于接口隔离原则的依赖注入实现
  • 原文地址:https://www.cnblogs.com/daichangya/p/12958825.html
Copyright © 2011-2022 走看看