美文网首页bug整理
Mina NIO通信相关bug整理

Mina NIO通信相关bug整理

作者: Mars_M | 来源:发表于2017-06-08 14:47 被阅读0次

1、java.lang.NegativeArraySizeException
发生在用负数长度创建数组时,原因是应用层报文设计数据最大长度为short,当数据超过short强制转换回丢失数据导致数值变负数。
所以在设计应用层报文时一定要注意数据的长度小于上限。本例中可以用int代替short让数据有2^32-1的长度。

2、滥用ExecutorFilter
Mina是基于REACTOR模型的,当连接建立对方发来消息首先由Processor线程池派出一个线程执行读取事件,经过粘包/缺包处理器处理,然后就完整的字节报文转换成上层应用报文。

假设解码器的代码为:
connector.getFilterChain().addLast("BaseFilter", new ProtocolCodecFilter(new BaseCodecFactory()));

如果在FilterChain之前加入代码:
connector.getFilterChain().addLast("threadpool",
new ExecutorFilter(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1)));

意思是解码器将不会在Processor线程池执行,而是由新创建的ExecutorFilter中的线程池执行。
这就导致了一个问题,假设数据长度8K,网络速度16K/S, 本地写入速度4K/S,明显网络速度大于本地IO速度,所以可能ExecutorFilter中的线程还没处理完一个完整应用层报文,Processor已经开始了下一个网络流的读取,从而导致数据错位。

本例中如果网络速度小于IO速度不会出现此问题,但是因为本地IO速度是动态的,当连接数增大IO遇到瓶颈很可能触发此问题。所以在FilterChain层加入线程池至少应该放在解码层后面,避免不同步处理数据的异常。

3、不同步发送文件分段导致文件写入不同步
虽然Reactor模型的SelectionKey.OP_READ 事件是按顺序读取SocketChannel的,但是如果在mina解码后配置:
connector.getFilterChain().addLast("threadpool",
new ExecutorFilter(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1)));
会导致处理上层报文的无序。

如果传输文件使用无序写入,就不能用FileOutputStream的追加模式:
FileOutputStream fos = new FileOutputStream(fileTask.zippedFilePath, true);
fos.write(filePart.data);
fos.flush();
fos.close();
因为写入是并发的,并不能保证其有序。

在并发环境下写入文件可以使用RandomAccessFile,支持在文件的指定位置写入:
RandomAccessFile randomAccessFile = new RandomAccessFile(fileTask.zippedFilePath, "rw");
long beginIndex = fileTask.fileSegmentSize*filePart.partId;
randomAccessFile.seek(beginIndex);
System.out.println("file length = "+randomAccessFile.length()+" , beginIndex = "+beginIndex);
randomAccessFile.write(filePart.data);
randomAccessFile.close();

因为文件处理是并行的,最后一段数据可能并不是最后处理完成的,所以怎么判断写入文件执行完毕?
发送文件分段时会传入当前文件分段的partId,在接收文件处理中使用AtomicInteger为partId计数,算出总计有多少个分段,再判断当前完成的分段数是否达到总数,就能够判断文件是否完全写入:

//每个线程执行完分段的写入将partId加1
int partId = fileTask.partId.incrementAndGet();

//算出总计有多少分段,用文件总大小除以分段的大小,如果有小数则加1取整
//最大传输4G的文件(2^32-1字节),超过则程序异常
int totalPart = (int) Math.ceil((double)fileTask.zippedFileSize/fileTask.fileSegmentSize);

if (partId==totalPart) {
//文件接收完毕
//md5验证
//通知对方
}

4、Processor线程池内的线程是固定的,要保证每个线程在运行期间不发生异常终止,否则Processor线程池不会重新创建线程。

相关文章

  • Mina NIO通信相关bug整理

    1、java.lang.NegativeArraySizeException发生在用负数长度创建数组时,原因是应用...

  • 基于Java NIO框架区别对比

    一.通信框架 流行基于Java NIO通信框架有Mina、Netty、Grizzly等。接下来说下它们之间的对比。...

  • NIO中存在的bug—epoll空轮询

    IO&NIO介绍 NIO中epoll空轮询表现 bug原因 JDK bug列表中有两个相关的bug报告: JDK-...

  • 第一篇 Java网络编程

    本篇主要从学习角度整理java的几个网络模型,包括: BIO通信模型 伪异步通信模型 NIO通信模型 NIO2.0...

  • Mina-tcp与NIO通信问题

    1.消息解码,编码问题 2.sessionIdle的几个用处 3、断线重连

  • 其他

    游戏开发相关 MINA:使用Java开发手游和页游服务器(对了还有Netty,也很猛的,都是基于NIO的) HP-...

  • Netty图解(二):进阶版的NIO

    进阶版--NIO通信server端部分代码: 进阶版--NIO通信client端部分代码: 进阶版--NIO通信执...

  • mina 源码解析(1)

    mina是一款网络应用框架, 它是基于java nio 的 通讯框架, 提供抽象的事件驱动异步的api。 mina...

  • NIO的epoll空轮询bug

    NIO的epoll空轮询bug JDK NIO的BUG,例如臭名昭著的epoll bug,它会导致Selector...

  • Netty图解(一):为何会有netty

    普通的NIO通信方式,服务端如下: 普通的NIO通信方式,客户端如下: 普通的NIO通信方式,执行和结果: 总结:...

网友评论

    本文标题:Mina NIO通信相关bug整理

    本文链接:https://www.haomeiwen.com/subject/ccuzfxtx.html