使用mina传输大字节数组

摘要:
当mina用于传输超过2k的数据时,mina将自动多次发送数据。因为数据是成批发送的,所以所有客户服务终端必须等待所有数据接收后才能解码,否则无法解码,或者只能读取一些文件。

使用mina传输超过2k以上的数据时(采用tcp方式,如果是UDP方式,好像一次传输的数据不能超过256字节,如果超过mina不会分批次发送,而tcp方式会分批次发送),mina会自动将这些数据分成多次发送。由于是分批次发送数据,所有客服端在接受数据时,需要等所有的数据接受完之后才能解码,否则无法解码,或者只能读取到部分文件。

以下是一个发送、接受大字节数组的主要代码
服务端向客服端发送字节数组

public class ImageDataEncoder extends ProtocolEncoderAdapter {
 @Override
 public void encode(IoSession session, Object message,
   ProtocolEncoderOutput out) throws Exception {
  CharsetEncoder charset = Charset.forName("UTF-8").newEncoder();
  ImageData image = (ImageData) message;
  IoBuffer buffer = IoBuffer.allocate(2048).setAutoExpand(true);
  buffer.putString(image.getYh(), charset);// 发送数据类型
  buffer.putInt(image.getLength());// 发送字节数组的总长度,共解码时使用
  buffer.put(image.getBimage());// 发送字节数据
  buffer.flip();
  out.write(buffer);
  buffer.free();
 }
}

ImageData.java
public class ImageData {
 private static final long serialVersionUID = 1L;
 private String yh = YHConstants.YH_IMG;// 数据类型
 public int length = 0;// 字节数组长度
 private byte[] bimage;// 待发送的字节数组
 private BufferedImage image;//将字节数组转换成图片文件
 public ImageData() {
 }
 public ImageData(byte[] bimage) {
  this.bimage = bimage;
 }
 public byte[] getBimage() {
  return bimage;
 }
 public BufferedImage getImage() {
  try {
   if (bimage.length > 0) {
    ByteArrayInputStream in = new ByteArrayInputStream(bimage);
    this.image = ImageIO.read(in);
    in.close();
   }
  } catch (RemoteException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  return this.image;
 }
 public int getLength() {
  return bimage.length;
 }
 public String getYh() {
  return yh;
 }
 public void setBimage(byte[] bimage) {
  this.bimage = bimage;
 }
 public void setYh(String yh) {
  this.yh = yh;
 }
}
YHConstants.java
public class YHConstants {
 public static final int LENGTH = 7;// 命令数据类型
 public static final String YH_CMD = "YH CMD ";// 命令数据类型
 public static final String YH_IMG = "YH IMG ";// 图片数据类型
}
客户端:
package com.seara.socket.codec;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import com.seara.socket.message.ImageData;
import com.seara.socket.message.YHConstants;
/**
 * 接收图片数据,由于图片数据比较大,tcp是采用分段式发送,所有需要等所有数据接收完之后才能解码
 * 
 * 解码原理:首先读取服务器端发送数据的总长度length,然后与当前的buff中的数据长度matchLength比较,如果matchLength>=
 * length则认为数据发送完毕, 否則将当前的buff保存起来,在下次发送buff之时合并为一个buff,然后在按照以上条件判断
 * 
 * @author seara
 * 
 */
public class ImageDataDecoder extends CumulativeProtocolDecoder {
 private final AttributeKey CONTEXT = new AttributeKey(this.getClass(),
   "context");
 @Override
 protected boolean doDecode(IoSession session, IoBuffer buff,
   ProtocolDecoderOutput out) throws Exception {
  CharsetDecoder charset = Charset.forName("UTF-8").newDecoder();
  System.out.println("继续解码......." + buff.remaining());
  // 取出context
  Context ctx = this.getContext(session);// 将contex从session中取出
  int length = ctx.getLength();// 数据总长度
  IoBuffer buffer = ctx.getBuffer();// 保存数据的buffer
  int matchLength = ctx.getMatchLength();// 目前已经发送的数据的总长度
  if (0 == length) {// 第一次取值
   String yh = buff.getString(YHConstants.LENGTH, charset);
   length = buff.getInt();
   matchLength = buff.remaining();
   ctx.setYh(yh);
   ctx.setLength(length);
  } else {
   matchLength += buff.remaining();
  }
  ctx.setMatchLength(matchLength);
  if (buff.hasRemaining()) {// 如果buff中还有数据
   buffer.put(buff);// 添加到保存数据的buffer中
   if (matchLength >= length) {// 如果已经发送的数据的长度>=目标数据的长度,则进行解码
    byte[] b = new byte[length];
    // 一定要添加以下这一段,否则不会有任何数据,因为,在执行buffer.put(buff)时buffer的起始位置已经移动到最后,所有需要将buffer的起始位置移动到最开始
    buffer.flip();
    buffer.get(b);
    ImageData image = new ImageData(b);
    out.write(image);
    System.out.println("解码完成.......");
    return true;
   } else {
    ctx.setBuffer(buffer);
   }
  }
  return false;// 返回false时,解码器就不会执行解码,返回true是在解码完成
 }
 /**
  * 定义一个内部类,用来封转当前解码器中的一些公共数据,主要是用于大数据解析
  * 
  * @author seara
  * 
  */
 public class Context {
  public IoBuffer buffer;
  public int length = 0;
  public int matchLength = 0;
  public String yh = "";
  public Context() {
   this.buffer = IoBuffer.allocate(1024).setAutoExpand(true);
  }
  public int getMatchLength() {
   return matchLength;
  }
  public void setMatchLength(int matchLength) {
   this.matchLength = matchLength;
  }
  public IoBuffer getBuffer() {
   return buffer;
  }
  public void setBuffer(IoBuffer buffer) {
   this.buffer = buffer;
  }
  public int getLength() {
   return length;
  }
  public void setLength(int length) {
   this.length = length;
  }
  public String getYh() {
   return yh;
  }
  public void setYh(String yh) {
   this.yh = yh;
  }
 }
 public Context getContext(IoSession session) {
  Context ctx = (Context) session.getAttribute(CONTEXT);
  if (ctx == null) {
   ctx = new Context();
   session.setAttribute(CONTEXT, ctx);
  }
  return ctx;
 }
}

免责声明:文章转载自《使用mina传输大字节数组》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇建立高并发模型需要考虑的点ASP.NET Dynamic Data Part.2(自定义动态数据网站)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

什么是session?

Session一般译作会话。从不同的层面看待session,它有着类似但不全然相同的含义。比如,在web应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在web应用的开发者开来,用户登录时我需要创建一个数据结构以存储用户的登录信息,这个结构也叫做session。因此在谈论session的时候要注意上下文环境...

实现自己的.NET Core配置Provider之Yaml

YAML是一种更适合人阅读的文件格式,很多大型的项目像Ruby on Rails都选择YAML作为配置文件的格式。如果项目的配置很少,用JSON或YAML没有多大差别。看看rails项目中的配置文件,如果用JSON写试试什么感受吧。 在《实现自己的.NET Core配置Provider之EF》中已经讲过配置的执行流程,这里不再复述,直接动手。 YamlCo...

android自定义控件概述

引子:   android SDK中会提供一些基础的控件以供开发。但是大多数情况下,这些基础的控件无法满足业务需求。本文主要说明自定义控件的分类,以及提供示例代码。   本文只做入门级选手阅读,或者 加深印象 或 温故而知新,大佬大神敬请绕道。 android控件的3种方式: 1)派生控件 : 从SDK已有的控件为基础,改变其部分特征,形成符合需求的自定...

django-实现登录短信验证

功能演示 核心任务 前端功能: 点击按钮Ajax调用发送验证码功能 输完验证码后Ajax调用验证功能 后端功能: 功能1:发送验证码功能 功能2:验证码检查 后台核心逻辑(不需要手写) 功能3:发短信 功能4:生成短信验证码(随机生成6位数字) 集成Redis 使用Redis代替session缓存, 存储数据! Redis集成到Djang...

Session 身份验证

1 Session 特点: (1)Session中的数据保存在服务器端; (2)Session中可以保存任意类型的数据; (2)Session默认的生命周期是20分钟,可以手动设置更长或更短的时间 web.config 配置: 程序webconfig配置: <system.web><sessionState mode="InProc" t...

jboss8+EJB3+MDB Queue

1)在使用jboss8即WildFly进行MDB的试验时首先要在jboss8中配置jms 队列。      我使用的是修改配置文件的方式配置Jms Queue队列。      进入jboss8 安装目录的standaloneconfiguration文件夹下:      因为使用的是standalone-full.xml文件,所以将该文件的文件名修改为st...