• NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信


    1、NIO超级陷阱

       之所以说NIO超级陷阱,就是因为我在本系列开头的那句话,因为使用缺陷导致客户业务系统瘫痪。当然,我对这个问题进行了很深的追踪,包括对MINA源码的深入了解,但其实之所以会出现这个问题,它的根不是MINA的原因,而是JDK底层的问题。

    JDK底层在实现nio时,为了能够唤醒等待在io上的线程,在windows平台使用了两个端口建立连接发消息实现。看如下代码:

    [java] view plain copy
     
     print?
    1. public class NIOTest {  
    2.   
    3.     @Test  
    4.     public void test1(){      
    5.   
    6.             final int MAXSIZE=1000;          
    7.             Selector [] sels = new Selector[ MAXSIZE];  
    8.             try{  
    9.                 for( int i = 0 ;i< MAXSIZE ;++i ) {  
    10.                     sels[i] = Selector.open();  
    11.                     Thread.sleep(1000*10);  
    12.                 }                         
    13.             }catch( Exception ex ){  
    14.                 ex.printStackTrace();  
    15.             }  
    16.     }  
    17. }  

    也就是说每调用一次Selector.open(),就会占用两个随机可用端口,相互通信--这就是问题的根源

        当然对于我们的项目来说,这个问题的解决需要分两步,首先限制端口数到用户可接受范围内,这个比较容易,我们可用只调用一次Selector.open()方法即可,使用单利模式;第二步,因为Selector.open()方法每次都是使用的系统当前可用的随机端口,所以就有可能导致占用客户业务端口的情况,因此我们必须把Selector.open()所开的端口限制在一定范围内,最好可以通过代码指定使用哪几个端口,但是直到现在我们都没有找到,如果亲们有方法的话,很感谢能够告诉我....,。


    Selector总结如下:
    Windows下,Selector.open()会自己和自己建立两条TCP链接。不但消耗了两个TCP连接和端口,同时也消耗了文件描述符。
    Linux下,Selector.open()会自己和自己建两条管道。同样消耗了两个系统的文件描述符。
    来源于:http://blog.csdn.net/haoel/article/details/2224055

        所以,现在我们现在就干脆用传统IO与MINA server通信吧。

    2、使用同步IO与MINA通信

    其实非常简单,唯一的难点就在于使用同步IO与MINA通信时,怎么编码和解码,还是看下面代码吧。

    server 端(用的MINA)

    [java] view plain copy
     
     print?
    1. /** 
    2.      * 初始化设置,启动服务 
    3.      */  
    4.     public void startServer() {  
    5.         logger.debug("mina server start");  
    6.         int port = SysEvnVar.managerPort;   
    7.         logger.debug("manager端口号:" + port);  
    8.         IoAcceptor acceptor = new NioSocketAcceptor();  
    9.         /** 日志设置 */  
    10.         acceptor.getFilterChain().addLast("logger", new LoggingFilter());  
    11.         //编码与解码工厂,使用的技术就是JDK提供的ObjectOutStream  
    12.         ObjectSerializationCodecFactory objsCodec=new ObjectSerializationCodecFactory();   
    13.         objsCodec.setDecoderMaxObjectSize(DEFAULTDECODER);  
    14.         objsCodec.setEncoderMaxObjectSize(DEFAULTDECODER);  
    15.         /** 数据转换,编码设置 */  
    16.         acceptor.getFilterChain().addLast(  
    17.                 "codec",  
    18.                 new ProtocolCodecFilter(objsCodec));  
    19.         /** 设置业务处理类 */  
    20.         acceptor.setHandler(serverHandler);  
    21.         /** 设置buffer容量 */  
    22.         acceptor.getSessionConfig().setReadBufferSize(DEFAULTBUFFERSIZE);  
    23.         /** 设置空闲时间 */  
    24.         acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, DEFAULTIDLETIME);  
    25.   
    26.         try {  
    27.             /** 绑定端口 */  
    28.             acceptor.bind(new InetSocketAddress(port));  
    29.             logger.info("mina server bind port ("+port+") sucess");  
    30.         } catch (IOException e) {  
    31.             logger.error("mina server bind port ("+port+") fail:" + e.getMessage(),e);  
    32.         }  
    33.     }  


    client端(使用同步IO)

    [java] view plain copy
     
     print?
    1. public void sendMessageToManager(HyRequest request) {  
    2.   
    3.         Socket socket = null;  
    4.         BufferedInputStream inBuff = null;  
    5.         OutputStream outBuff = null;  
    6.         try {  
    7.             Integer port = Integer.parseInt(hyGlobalConfigureCacheImpl.get(  
    8.                     "managerPort").toString());  
    9.             String host = hyGlobalConfigureCacheImpl.get("managerIp")  
    10.                     .toString();  
    11.             socket = new Socket(host, port);  
    12.   
    13.             inBuff = new BufferedInputStream(new DataInputStream(  
    14.                     socket.getInputStream()));  
    15.             outBuff = socket.getOutputStream();  
    16.   
    17.             String json = HyJsonUtil.reqeustToJsonStr(request);  
    18.   
    19.             //编码开始,使MINA能够解析  
    20.             IoBuffer buf = IoBuffer.allocate(64);  
    21.             buf.setAutoExpand(true);  
    22.             buf.putObject(json);  
    23.   
    24.             buf.flip();  
    25.             byte[] bytes =new byte[buf.limit()];              
    26.             buf.get(bytes);    
    27.             //编码结束,直接输出到客户端  
    28.               
    29.             outBuff.write(bytes);  
    30.             outBuff.flush();  
    31.   
    32.             if(request.getOperation() != null && !"quit".equals(request.getOperation())){  
    33.                 String allreadstr = new String();  
    34.   
    35.                 byte[] b = new byte[512 * 1024];  
    36.                 int len;  
    37.                 byte[] tmp = new byte[0];  
    38.                 if ((len = inBuff.read(b)) != -1) {  
    39.                     tmp = new byte[len];  
    40.                     System.arraycopy(b, 0, tmp, 0, len);  
    41.                 }  
    42.                 loger.debug("len:"+len);  
    43.   
    44.                 //解码开始,byte[]为MINA传过来的数据  
    45.                 IoBuffer in = IoBuffer.wrap(tmp);  
    46.                 Object obj = null;  
    47.                 try {  
    48.                     loger.debug("in:"+in);  
    49.                     obj = in.getObject();  
    50.                     //解码结束  
    51.                     loger.debug("parse success");  
    52.                 } catch (Exception e) {  
    53.                     // TODO Auto-generated catch block  
    54.                     e.printStackTrace();  
    55.                     loger.debug("go to exception");  
    56.                     loger.warn("nio parse exception",e);  
    57.                     obj = "exception";  
    58.                 }  
    59.                 allreadstr = (String) obj;  
    60.   
    61.                   
    62.                 loger.info("receive message from "  
    63.                         + socket.getRemoteSocketAddress().toString() + ",message:"  
    64.                         + allreadstr);  
    65.                 // 请求消息转换为HyResponse对象  
    66.                 HyResponse response = HyJsonUtil.getHyResponse(allreadstr);  
    67.                 HyRequest hyrequest = new HyRequest();  
    68.                 hyResponseDispatcher = hyClientHandler.getHyResponseDispatcher();  
    69.                 hyResponseDispatcher.responseProcess(hyrequest, response);  
    70.                 if (hyrequest.getOperation() != null) {                   
    71.                     sendMessageToManager2(hyrequest);  
    72.                 }  
    73.   
    74.             }  
    75.               
    76.   
    77.         } catch (Exception e) {  
    78.             e.printStackTrace();  
    79.         } finally {  
    80.             try {  
    81.                 if(null != outBuff)  
    82.                 outBuff.close();  
    83.             } catch (IOException e1) {  
    84.                 // TODO Auto-generated catch block  
    85.                 e1.printStackTrace();  
    86.             }  
    87.             try {  
    88.                 if(null != inBuff)  
    89.                 inBuff.close();  
    90.             } catch (IOException e1) {  
    91.                 // TODO Auto-generated catch block  
    92.                 e1.printStackTrace();  
    93.             }  
    94.   
    95.             if (socket != null) {  
    96.                 try {  
    97.                     socket.close();  
    98.                 } catch (IOException e) {  
    99.                 }  
    100.             }  
    101.         }  
    102.   
    103.     }  

    看代码里面的注释,怎么编码和解码,其实我是直接看MINA源码,把MINA的编码和解码方法工具类直接拷到了我们的client端,这样就轻松的实现使用同步IO和MINA进行通信。

  • 相关阅读:
    Django其五
    数据库操作
    小程序navigateBack,子页面传值给父页面
    深拷贝
    sql语句case when 以及left()
    IE高级配置中,存在SSL支持协议,例如SSL TLS。
    linux服务器后台运行服务
    各种浏览器文件下载
    localStorage sessionStorage 用法
    url编码乱码问题解决
  • 原文地址:https://www.cnblogs.com/duanxz/p/6754612.html
Copyright © 2020-2023  润新知