【MinaFile】【十三】【2.0】关于粘包的处理

来源:互联网 发布:java前端面试 编辑:程序博客网 时间:2024/05/03 10:32

我们在Mina服务器对文件进行自定义解码的时候,继承了类CumulativeProtocolDecoder。

这个类默认的字节数处理是2048,所以当文件超过了2048个字节之后,服务器解码器就会报错java.nio.BufferUnderflowException 这个异常。

以为需要解析的字节为4096KB,但是Mina能够一次性处理的只有2048个字节,所以就会报错。很简单吧?

解决办法,重写一下第【十一】章里面的ByteProtocalDecoder类


/** * 这个是服务器对客户端发来的消息进行解码 * 继承CumulativeProtocolDecoder * 实现doDecode * 父类会将数据读取完之后,再调用实现的方法doDecode。 * 如果成功读取完之后,服务器会去Handle中进行业务处理。 * 对发来的文件进行业务处理,比如说保存之类的 动作。 * @author king_fu * */public class ByteProtocalDecoder extends CumulativeProtocolDecoder{private static final Logger LOGGER = LoggerFactory.getLogger(ByteProtocalDecoder.class);public static final int MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1Gprivate boolean isFinish = false; // 是否已经处理所有数据private static boolean isFirst = true; // 是否是第一次进来private ByteFileMessage bfm = new ByteFileMessage(); // 保存对象private static IoBuffer newIoBuffer = IoBuffer.allocate(0).setAutoExpand(true) ;public ByteProtocalDecoder() {}@Overrideprotected boolean doDecode(IoSession session, IoBuffer in,ProtocolDecoderOutput out) throws Exception {LOGGER.info("服务器对客户端发来的消息进行解码。解码开始");LOGGER.info("limit:"+in.limit());LOGGER.info("remaining:"+in.remaining());try{ // 这个方法的调用是判断IoBuffer里的数据是否满足一条消息了// dataLength = getInt(position());用绝对值的方式读取,position不会移动。  if ((!isFirst) || in.prefixedDataAvailable(4, MAX_FILE_SIZE)) {  this.readFile(in);  if(isFinish){  // 解析完成  out.write(bfm);  }else{  return true;  }    }else{  in.position(0);  LOGGER.info("不符合读取条件");  return false;  }}catch (Exception e) {LOGGER.info("服务器解码过程中发生错误",e);return false;}return true;}private void readFile(IoBuffer in) throws CharacterCodingException  {CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();in.position(0);// ByteFileMessage bfm = new ByteFileMessage();if(isFirst){bfm.setSeq(in.getInt()); //序号bfm.setFileNameLength(in.getInt()); // 文件名长度(字节)bfm.setFileName(in.getString(bfm.getFileNameLength(),decoder)); // 文件名。UTF-8格式bfm.setFileStreamLength(in.getInt()); // 文件长度(字节)}//如果读的文件的长度(字节:比如4096个字节),远远大于这个缓冲区的容量(最大容量:2048字节),那么需要进行把一个个包黏起来byte[] byteValue = null;if(bfm.getFileStreamLength() > in.limit()){/*int dealDataLen = in.limit(); // 本次要处理的数据长度byteValue = new byte[dealDataLen];*/bfm.setFileStreamLength(bfm.getFileStreamLength() - in.limit());IoBuffer bufTmp = null;if(isFirst){ // 第一次LOGGER.info("【服务器解析】继续接受in:" + in.remaining());bufTmp = IoBuffer.allocate(newIoBuffer.remaining() +in.remaining() ).setAutoExpand(true);isFirst = false;}else{LOGGER.info("【服务器解析】继续接受in:" + in.remaining());bufTmp = IoBuffer.allocate(newIoBuffer.remaining() + in.remaining() ).setAutoExpand(true);}bufTmp.order(newIoBuffer.order());bufTmp.put(newIoBuffer);bufTmp.put(in);bufTmp.flip();newIoBuffer = bufTmp;isFinish = false; // 数据未读取完。LOGGER.info("【服务器解析】未解析数据:" + newIoBuffer.remaining() + "字节");}else{IoBuffer bufTmp = IoBuffer.allocate( newIoBuffer.remaining() + in.remaining() ).setAutoExpand(true);bufTmp.order(newIoBuffer.order());bufTmp.put(newIoBuffer);bufTmp.put(in);bufTmp.flip();newIoBuffer = bufTmp;int remainingData = newIoBuffer.remaining(); // 总共多少LOGGER.info("【服务器解析】文件需要解析多少字节:" + remainingData);byteValue = new byte[remainingData];newIoBuffer.get(byteValue);LOGGER.info("当前读取的文件大小:" +  remainingData/1024 + "KB"  );bfm.setFileStream(byteValue);isFinish = true;LOGGER.info("【服务器解析】解析完成");}//LOGGER.info(new String(). bfm.getFileStream());//return isFinish;    }}

最新代码已经更新在github中,欢迎fork。

项目名:MinaFile


1 0
原创粉丝点击