使用 mina 传输大字节数组
转载自: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 传输大字节数组的更多相关文章
- Mina传输大数组,多路解码,粘包问题的处理
我的实际情况: 1,传递的业务数据种类很多,这就决定了我们要用多路解码器,MINA的中文手册提供的是DemuxingProtocolCodecFactory; 2,,有的数据长度达到8K,网上有资料说 ...
- mina 字节数组编解码器的写法 II
I 里面的写法不够严谨,这也是我之前说它简陋的主要原因,下面来个更加严谨.完整一点儿的: ByteArrayEncoder.java package org.bruce.mina.cpp.codec; ...
- C#后台接java接口传输字节数组(byte[])
事情是这样的C#t代码之前接的WCF接口,后来那边统一改为java的接口,我是用的HttpClient从后台发请求调用的java接口,其他接口都很顺利,是的....知道遇到一个需要传byte[]类型数 ...
- java对获取的字节数组进行处理
java对获取的字节数组bytes[]进行处理: 第一种,直接将该字节数组转换为字符串(部分): String content = ,); //从位置0开始获取2个字节 这样,对获取的数据报进行全部转 ...
- WebAPI中发送字节数组
今天工作中遇到了一个情景: 前端向后台发送一个请求,希望后台返回一组数据,由于后台返回的数据量很大,希望尽可能压缩响应的大小 我的想法:后台将数据(Short的数组)直接转换成Byte[] 然后将b ...
- IO流处理文件读取到字节数组,再从字节数组读取到文件,Java实现
package cn.zhang.io; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; impo ...
- Java将文件转为字节数组
Java将文件转为字节数组 关键字:文件,文件流,字节流,字节数组,二进制 摘要:最近工作中碰到的需求是,利用http传输二进制数据到服务器对应接口,需要传输userId, file(加密后)等一系列 ...
- WCF传输大数据的设置
在从客户端向WCF服务端传送较大数据(>65535B)的时候,发现程序直接从Reference的BeginInvoke跳到EndInvoke,没有进入服务端的Service实际逻辑中,怀疑是由于 ...
- 基于RMI服务传输大文件的完整解决方案
基于RMI服务传输大文件,分为上传和下载两种操作,需要注意的技术点主要有三方面,第一,RMI服务中传输的数据必须是可序列化的.第二,在传输大文件的过程中应该有进度提醒机制,对于大文件传输来说,这点很重 ...
随机推荐
- python简单网络服务器
对于服务器来说建立TCP连接的过程分为4步: 1.建立socket对象:这里与客户端一样,依然是: s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) ...
- [网络]远程访问局域网svn服务器[转]
转至:http://8474832.blog.51cto.com/8464832/1555449 打开路由器访问界面 选择转发规则->端口映射-新建 在弹出的界面中填写相应的端口号了内网ip 填 ...
- JDBC和JPA调用储存过程 接收存储过程有返回值
============jdbc==========================================--java代码:一个输出参数--String connURL = null;Con ...
- EASYUI DATAGRID 多列复选框CheckBox
主要实现: 用的 easyui 1.3.2 实现多个复选框列,各列互不影响.能够实现全选.主要部门用红色标记了的. easyui datagrid 初始化: <script> functi ...
- C:函数指针、回调函数
函数指针 是一个指针,指向函数的指针,指针存放的都是地址,所以函数指针存放的是函数的地址.数组名就是数组的首地址,函数名就是函数的首地址.与数组类似. 代码demo int (*p) (int ,in ...
- Hadoop集群基准测试
hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.2.0-tests.jar TestDFSIO -wri ...
- Rstudio安装
1.https://www.r-project.org/下载R语言(注意32位还是46位系统). 2.安装R,尽量默认安装路径,安装路径不要有中文. 3.https://www.rstudio.com ...
- Beyond Compare3 添加到右键菜单
Beyond Compare 是个优秀的工具,我们经常用于对比文件和文件夹,右键点点就可以调用对比,着实很方便.但从3.2版本之前,我们可以从设置中将bc关联到文件夹和文件右键,但之后的版本已经找不到 ...
- 开发过程中常用的Linux命令
做Java开发好几年了,部署JavaWeb到服务器上,一般都选择Linux,Linux作为服务器真是不二之选,高性能,只要熟悉Linux,操作快捷,效率很高. 总结一下工作中常用的Linux命令备忘: ...
- 为DELL inspiron 14R安装CentOS X64 6.4
今天接到一个任务,为DELL inspiron 14R安装CentOS X64 6.4,本以为这是小菜一碟,不算个啥,大大小小安装LINUX CENTOS 不下上百次了,还怕这个?结果,各种碰壁... ...