1、NIO超级陷阱

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

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

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

也就是说每调用一次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)

  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. try {
  26. /** 绑定端口 */
  27. acceptor.bind(new InetSocketAddress(port));
  28. logger.info("mina server bind port ("+port+") sucess");
  29. } catch (IOException e) {
  30. logger.error("mina server bind port ("+port+") fail:" + e.getMessage(),e);
  31. }
  32. }

client端(使用同步IO)

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

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

NIO框架之MINA源码解析(五):NIO超级陷阱和使用同步IO与MINA通信的更多相关文章

  1. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

  2. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

  3. ReactiveCocoa源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  4. ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  5. iOS即时通讯之CocoaAsyncSocket源码解析五

    接上篇:iOS即时通讯之CocoaAsyncSocket源码解析四         原文 前言: 本文为CocoaAsyncSocket Read篇终,将重点涉及该框架是如何利用缓冲区对数据进行读取. ...

  6. Spring 源码解析之DispatcherServlet源码解析(五)

    spring的整个请求流程都是围绕着DispatcherServlet进行的 类结构图 根据类的结构来说DispatcherServlet本身也是继承了HttpServlet的,所有的请求都是根据这一 ...

  7. Mybaits 源码解析 (十)----- 全网最详细,没有之一:Spring-Mybatis框架使用与源码解析

    在前面几篇文章中我们主要分析了Mybatis的单独使用,在实际在常规项目开发中,大部分都会使用mybatis与Spring结合起来使用,毕竟现在不用Spring开发的项目实在太少了.本篇文章便来介绍下 ...

  8. NIO框架之MINA源码解析(四):粘包与断包处理及编码与解码

    1.粘包与段包 粘包:指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.造成的可能原因: 发送端需要等缓冲区满才发送出去,造成粘包 接收 ...

  9. NIO框架之MINA源码解析(转)

    http://blog.csdn.net/column/details/nio-mina-source.html http://blog.csdn.net/chaofanwei/article/det ...

随机推荐

  1. 基于Flask开发web微信

    1. 获取二维码 app.py import re import time import requests from flask import Flask,render_template app = ...

  2. Bow and Arrow Rigging in Blender

    https://www.youtube.com/watch?v=jpsd0Aw1qvA 新建骨架,由如下图3部分组成: Bone.000.Top ~ Bone.015.Top (上半部分16节骨骼) ...

  3. 用Python开发Zeroc Ice应用

    Zeroc Ice简介   Zeroc ICE(Internet Communications Engine ,互联网通信引擎)是目前功能比较强大和完善的RPC框架,支持跨平台.跨语言调用.它非常灵活 ...

  4. oracle审计的激活与取消

    审计audit用户见识用户所执行的操作,并且oracle会将审计跟踪结果存放到os文件或数据库中 激活审计 conn /as sysdba show parameter audit_sys_opera ...

  5. (android高仿系列)今日头条 --新闻阅读器 (二)

    高仿今日头条 --- 第一篇:(android高仿系列)今日头条 --新闻阅读器 (一)    上次,已经完毕了头部新闻分类栏目的拖动效果. 这篇文章是继续去完好APP 今日头条  这个新闻阅读器的其 ...

  6. CLR(Common Language Runtime) 公共语言运行库

    .NET Core 使用 CoreCLR .NET Framework 使用CLR. 1. 将代码编译为IL (Intermediate Language) 2. CLR 把IL 编译为平台专用的本地 ...

  7. 图的最短路径——dijkstra算法和Floyd算法

    dijkstra算法 求某一顶点到其它各个顶点的最短路径:已知某一顶点v0,求它顶点到其它顶点的最短路径,该算法按照最短路径递增的顺序产生一点到其余各顶点的所有最短路径. 对于图G={V,{E}};将 ...

  8. ThinkPHP 5.2 出 RC1 版本 RC 是什么意思呢?

    ThinkPHP 5.2 出 RC1 版本 RC 是什么意思呢? RC 的意思是软件候选版本,就是不会有很大的改变,主要还是在除错方面. 来自收集的资料1引用: Alpha:是内部测试版,一般不向外部 ...

  9. 论 数据库 B Tree 索引 在 固态硬盘 上 的 离散存储

    传统的做法 , 数据库 的 B Tree 索引 在 磁盘上是 顺序存储 的 , 这是考虑到 磁盘 机械读写 的 特性 . 实际上 , B Tree 是一个 树形结构 , 可以采用 链式 存储 , 就是 ...

  10. Dynamic Signals and Slots

    Ref https://doc.qt.io/archives/qq/qq16-dynamicqobject.html Trolltech | Documentation | Qt Quarterly ...