转载自:http://seara520.blog.163.com/blog/static/16812769820103214817781/

使用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

package org.bruce.mina.cpp.client;

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

package org.bruce.mina.cpp.client;

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 ";// 图片数据类型
}

客服端:

解码器:分段发送的解码器一定要继承CumulativeProtocolDecoder ,这个是专门用来实现这种解码的

package org.bruce.mina.cpp.client;

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 传输大字节数组的更多相关文章

  1. Mina传输大数组,多路解码,粘包问题的处理

    我的实际情况: 1,传递的业务数据种类很多,这就决定了我们要用多路解码器,MINA的中文手册提供的是DemuxingProtocolCodecFactory; 2,,有的数据长度达到8K,网上有资料说 ...

  2. mina 字节数组编解码器的写法 II

    I 里面的写法不够严谨,这也是我之前说它简陋的主要原因,下面来个更加严谨.完整一点儿的: ByteArrayEncoder.java package org.bruce.mina.cpp.codec; ...

  3. C#后台接java接口传输字节数组(byte[])

    事情是这样的C#t代码之前接的WCF接口,后来那边统一改为java的接口,我是用的HttpClient从后台发请求调用的java接口,其他接口都很顺利,是的....知道遇到一个需要传byte[]类型数 ...

  4. java对获取的字节数组进行处理

    java对获取的字节数组bytes[]进行处理: 第一种,直接将该字节数组转换为字符串(部分): String content = ,); //从位置0开始获取2个字节 这样,对获取的数据报进行全部转 ...

  5. WebAPI中发送字节数组

    今天工作中遇到了一个情景: 前端向后台发送一个请求,希望后台返回一组数据,由于后台返回的数据量很大,希望尽可能压缩响应的大小 我的想法:后台将数据(Short的数组)直接转换成Byte[]  然后将b ...

  6. IO流处理文件读取到字节数组,再从字节数组读取到文件,Java实现

    package cn.zhang.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; impo ...

  7. Java将文件转为字节数组

    Java将文件转为字节数组 关键字:文件,文件流,字节流,字节数组,二进制 摘要:最近工作中碰到的需求是,利用http传输二进制数据到服务器对应接口,需要传输userId, file(加密后)等一系列 ...

  8. WCF传输大数据的设置

    在从客户端向WCF服务端传送较大数据(>65535B)的时候,发现程序直接从Reference的BeginInvoke跳到EndInvoke,没有进入服务端的Service实际逻辑中,怀疑是由于 ...

  9. 基于RMI服务传输大文件的完整解决方案

    基于RMI服务传输大文件,分为上传和下载两种操作,需要注意的技术点主要有三方面,第一,RMI服务中传输的数据必须是可序列化的.第二,在传输大文件的过程中应该有进度提醒机制,对于大文件传输来说,这点很重 ...

随机推荐

  1. 实现jsp网站添加到收藏夹

    var ctrl = (navigator.userAgent.toLowerCase()).indexOf('mac') != -1 ? 'Command/Cmd': 'CTRL';         ...

  2. Eclipse设置、调优、使用

    eclipse调优 一般在不对eclipse进行相关设置的时候,使用eclipse总是会觉得启动好慢,用起来好卡,其实只要对eclipse的相关参数进行一些配置,就会有很大的改善. 加快启动速度 1. ...

  3. Jmeter_初步认识随笔

    1. 简介 Apache JMeter是100%纯java桌面应用程序,被设计用来测试客户端/服务器结构的软件(例如web应用程序).它可以用来测试包括基于静态和动态资源程序的性能,例如静态文件,Ja ...

  4. Decode放在where条件后的新用法

    今天遇到一种特殊情况的查询,在查询某表时,要通过判断其中一个字段的值再用其他字段作为条件查询,比如有3个字段 columnA,columnBm,columnC,columnA的值由两个——分别是0和1 ...

  5. 窥探EasyMock(1)基础使用篇

    EasyMock的应用分为5步: 1. 使用 EasyMock 生成 Mock 对象: SomeInterface mockObj = createMock(SomeInterface.class); ...

  6. iepngfix.htc让PNG-24在IE6中透明的方法(转)

    add:360用的一个方法: <!--[if IE 6]> <script src="http://se.360.cn/js/DD_belatedPNG.js"& ...

  7. wikioi 3038 3n+1问题

    题目描述 Description 3n+1问题是一个简单有趣而又没有解决的数学问题.这个问题是由L. Collatz在1937年提出的.克拉兹问题(Collatz problem)也被叫做hailst ...

  8. Hadoop on Mac with IntelliJ IDEA - 10 陆喜恒. Hadoop实战(第2版)6.4.1(Shuffle和排序)Map端 内容整理

    下午对着源码看陆喜恒. Hadoop实战(第2版)6.4.1  (Shuffle和排序)Map端,发现与Hadoop 1.2.1的源码有些出入.下面作个简单的记录,方便起见,引用自书本的语句都用斜体表 ...

  9. C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem

    class TestThread { static void Main() { //使用WaitHandle静态方法阻止一个线程,直到一个或多个同步对象接收到信号 WaitHandle[] waitH ...

  10. Codeforces Round #342 (Div. 2) D. Finals in arithmetic 贪心

    D. Finals in arithmetic 题目连接: http://www.codeforces.com/contest/625/problem/D Description Vitya is s ...