我的实际情况:

1,传递的业务数据种类很多,这就决定了我们要用多路解码器,MINA的中文手册提供的是DemuxingProtocolCodecFactory;

2,,有的数据长度达到8K,网上有资料说Mina在传输数据超过2K的情况下,会分片传输,因此要考虑如何来接收;

3,若数据发送很快,或者网络状况不佳,很容易出现粘包的情况,这也是要解决的问题。

1)针对多路解码:

编码器:

将编码器继承MessageEncoder<T>,T是你编码的对象的类,此中我是要编码Requstwork类;其中GetBytes()是我自己定义的将对象的数据组成字节数组的函数;

public class RequstNetworkEncoder implements MessageEncoder<RequstNetwork>{
@Override
public void encode(IoSession ioSession, RequstNetwork requstNetwork, ProtocolEncoderOutput out)
throws Exception {
if (requstNetwork != null) {
byte[] bytes1 = GetBytes(requstNetwork);
int capacity = bytes1.length;
IoBuffer buffer = IoBuffer.allocate(capacity, false);
buffer.setAutoExpand(true);
buffer.put(bytes1);
buffer.flip();
out.write(buffer);
}
}
}

对应的解码器:

public class RequstNetworkDecoder implements MessageDecoder {
@Override
public MessageDecoderResult decodable(IoSession ioSession, IoBuffer ioBuffer) {
if(ioBuffer.remaining()<2){
//还没有达到不同数据的标志位的地方
return MessageDecoderResult.NEED_DATA;
}
else{
ioBuffer.position(1);
byte b=ioBuffer.get();
if (b==(此处为区分不同数据的标志)){
return MessageDecoderResult.OK; }
else{
return MessageDecoderResult.NOT_OK;
}
}
} @Override
public MessageDecoderResult decode(IoSession ioSession, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {
RequstNetworkReply reply=new RequstNetworkReply();
//自己解码的过程
out.write(reply);
return MessageDecoderResult.OK;
} @Override
public void finishDecode(IoSession ioSession, ProtocolDecoderOutput protocolDecoderOutput) throws Exception { }
}

编解码工厂:

public class MyProtocolCodecFactory extends DemuxingProtocolCodecFactory {

    public MyProtocolCodecFactory(){
super.addMessageEncoder(RequstNetwork.class,RequstNetworkEncoder.class);
super.addMessageDecoder(RequstNetworkDecoder.class); }
}

针对大数组的传输和粘包,修改了一下网上的做法:

public class RequestPlanDecoder extends CumulativeProtocolDecoder {

    private final AttributeKey CONTEXT = new AttributeKey(getClass(),
"context"); @Override
protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception { Context ctx =getContext(session);//获取session 的context long matchCount=ctx.getMatchLength();//目前已获取的数据
long length=ctx.getLength();//数据总长度
IoBuffer buffer=ctx.getBuffer();//数据存入buffer //第一次取数据
if(length==0){
length=in.getLong();
//保存第一次获取的长度
ctx.setLength(length);
matchCount=in.remaining();
ctx.setMatchLength(matchCount);
}
else{
matchCount+=in.remaining();
ctx.setMatchLength(matchCount);
}
ctx.setMatchLength(matchCount);
if (in.hasRemaining()) {
// 如果buff中还有数据
buffer.put(in);
// 添加到保存数据的buffer中
if (matchCount >= length) {
////自己解码的部分///////
if(buffer.remaining() > 0) {
//如果读取一个完整包内容后还粘了包,就让父类再调用一次,进行下一次解析
IoBuffer temp = IoBuffer.allocate(1024).setAutoExpand(true);
temp.put(buffer);
temp.flip();
in.sweep();
//清空数据
in.put(temp);
}
ctx.reset();//清空
return true;
} else {
ctx.setBuffer(buffer);
return false;
}
}
return false;
} //获取session的context
public Context getContext(IoSession session) {
Context ctx = (Context) session.getAttribute(CONTEXT);
if (ctx == null) {
ctx = new Context();
session.setAttribute(CONTEXT, ctx);
}
return ctx;
}
/** * 定义一个内部类,用来封转当前解码器中的一些公共数据,主要是用于大数据解析 **/
private class Context { public IoBuffer buffer; public long length = 0; public long matchLength = 0; public Context() {
buffer = IoBuffer.allocate(1024).setAutoExpand(true);
}
public void setBuffer(IoBuffer buffer) {
this.buffer = buffer;
}
public void setLength(long length) {
this.length = length;
}
public void setMatchLength(long matchLength) {
this.matchLength = matchLength;
}
public IoBuffer getBuffer() {
return buffer;
}
public long getLength() {
return length;
}
public long getMatchLength() {
return matchLength;
}
public void reset(){
this.buffer.clear();
this.length=0;
this.matchLength=0;
} }
}

我想让传大数组的解码器能和其他解码器一起共用,通过查看官方的MINA API直到MessageDecoder就是继承了CumulativeProtocolDecoder,于是就做了如下结合:

public class RequestPlanDecode implements MessageDecoder  {
private final AttributeKey CONTEXT = new AttributeKey(getClass(),
"context");
@Override
public MessageDecoderResult decodable(IoSession ioSession, IoBuffer in) {
if(in.remaining()<2){
return MessageDecoderResult.NEED_DATA;
}
else{
byte b1=in.get();
byte b2=in.get();
if(b2==<span style="font-family: Arial, Helvetica, sans-serif;">(此处为区分不同数据的标志)</span>){
return MessageDecoderResult.OK;
}
else {
return MessageDecoderResult.NOT_OK;
}
}
} @Override
public MessageDecoderResult decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {
//=================结合CumulativeProtocolDecoder================//
Context ctx =getContext(session);//获取session 的context long matchCount=ctx.getMatchLength();//目前已获取的数据
long length=ctx.getLength();//数据总长度
IoBuffer buffer=ctx.getBuffer();//数据存入buffer //第一次取数据
if(length==0){
length=in.getLong();
//保存第一次获取的长度
ctx.setLength(length);
matchCount=in.remaining();
ctx.setMatchLength(matchCount);
}
else{
matchCount+=in.remaining();
ctx.setMatchLength(matchCount);
}
if (in.hasRemaining()) {// 如果buff中还有数据
buffer.put(in);// 添加到保存数据的buffer中
if (matchCount >= length) {// 如果已经发送的数据的长度>=目标数据的长度,则进行解码
////自己解码的部分/////// if(buffer.remaining() > 0) {////解决粘包
IoBuffer temp = IoBuffer.allocate(1024).setAutoExpand(true);
temp.put(buffer);
temp.flip();
in.sweep();
in.put(temp);
}
ctx.reset();
return MessageDecoderResult.OK; } else {
ctx.setBuffer(buffer);
return MessageDecoderResult.NEED_DATA;
}
}
return MessageDecoderResult.NEED_DATA;
} @Override
public void finishDecode(IoSession ioSession, ProtocolDecoderOutput protocolDecoderOutput)
throws Exception { }
/////////////////////////////////////结合CumulativeProtocolDecoder/////////////////////////////////////////////////
//获取session的context
public Context getContext(IoSession session) {
Context ctx = (Context) session.getAttribute(CONTEXT);
if (ctx == null) {
ctx = new Context();
session.setAttribute(CONTEXT, ctx);
}
return ctx;
}
/**
* 定义一个内部类,用来封转当前解码器中的一些公共数据,主要是用于大数据解析
*
*/
private class Context {
public IoBuffer buffer;
public long length = 0;
public long matchLength = 0; public Context() {
buffer = IoBuffer.allocate(1024).setAutoExpand(true);
} public void setBuffer(IoBuffer buffer) {
this.buffer = buffer;
} public void setLength(long length) {
this.length = length;
}
public void setMatchLength(long matchLength) {
this.matchLength = matchLength;
} public IoBuffer getBuffer() { return buffer;
} public long getLength() {
return length;
} public long getMatchLength() {
return matchLength;
} public void reset(){
this.buffer.clear();
this.length=0;
this.matchLength=0;
}
} }

Mina传输大数组,多路解码,粘包问题的处理的更多相关文章

  1. 使用 mina 传输大字节数组

    转载自:http://seara520.blog.163.com/blog/static/16812769820103214817781/ 使用mina传输超过2k以上的数据时(采用tcp方式,如果是 ...

  2. Socket传输简单的信息以及粘包问题的解决

    一.简单的socket程序——传输简短文字: # -*- coding: utf-8 -*- # -*- Author: WangHW -*- import socket whw_client = s ...

  3. python网络编程-socket上传下载文件(包括md5验证,大数据发送,粘包处理)

    ftp server 1) 读取文件名 2)检查文件是否存在 3)打开文件 4)检查文件大小 5)发送文件大小给客户端 6)等客户端确认 7)开始边读边(md5计算)发数据 8)给客户端发md5 ft ...

  4. socket编程 TCP 粘包和半包 的问题及解决办法

    一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...

  5. 【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案

    引子 现如今手游开发中网络编程是必不可少的重要一环,如果使用的是TCP协议的话,那么不可避免的就会遇见TCP粘包和拆包的问题,马三觉得haifeiWu博主的 TCP 粘包问题浅析及其解决方案 这篇博客 ...

  6. TCP粘包问题的解决方案01——自定义包体

      粘包问题:应用层要发送数据,需要调用write函数将数据发送到套接口发送缓冲区.如果应用层数据大小大于SO_SNDBUF,那么,可能产生这样一种情况,应用层的数据一部分已经被发送了,还有一部分还在 ...

  7. c# socket 解决粘包,半包

    处理原理: 半包:即一条消息底层分几次发送,先有个头包读取整条消息的长度,当不满足长度时,将消息临时缓存起来,直到满足长度再解码 粘包:两条完整/不完整消息粘在一起,一般是解码完上一条消息,然后再判断 ...

  8. TCP 粘包问题浅析及其解决方案

    最近一直在做中间件相关的东西,所以接触到的各种协议比较多,总的来说有TCP,UDP,HTTP等各种网络传输协议,因此楼主想先从协议最基本的TCP粘包问题搞起,把计算机网络这部分基础夯实一下. TCP协 ...

  9. PYTHON-TCP 粘包

    1.TCP的模板代码 收发消息的循环 通讯循环 不断的连接客户端循环 连接循环 判断 用于判断客户端异常退出(抛异常)或close(死循环) 半连接池backlog listen(5) 占用的是内存空 ...

随机推荐

  1. MFC 单文档消息执行顺序。

    theApp构造, InitInstance void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO* lpMMI) BOOL CMyFrameWnd::OnNcCr ...

  2. 微信nickname乱码及mysql编码格式设置(utf8mb4)

    微信nickname乱码及mysql编码格式设置(utf8mb4) 今天在写微信公众平台项目时,写到一个用户管理模块,接口神马的已经调试好了,于是将用户从微信服务器保存到本地数据库,发现报错: jav ...

  3. 【转】C#大文件读取和查询--内存映射

    笔者最近需要快速查询日志文件,文件大小在4G以上. 需求如下: 1.读取4G左右大小的文件中的指定行,程序运行占用内存不超过500M. 2.希望查询1G以内容,能控制在20s左右. 刚开始觉得这个应该 ...

  4. 前端菜鸟的编程之路之css的用法

    /* * * 固定特殊类 * */ /* ===========固定宽度*============= */ .ld-with80{width: 80px} .ld-with50{width: 50px ...

  5. 配置Struts.xml DTD文件报错

    报错信息为: The content of element type "struts" must match "((package|include|bean|  cons ...

  6. 使用jxl,poi读取excel文件

    作用:在java后台添加一个方法,读取导入的excel内容,根据需要返回相应的sql语句,以完成对临时表的插入操作. 使用jxl读取excel文件 package com.sixthf.bi.sapp ...

  7. websql的添加和查询

    openDatabase 我们可以使用这样简单的一条语句,创建或打开一个本地的数据库对象 var db = openDatabase('testDB', '1.0', 'Test DB', 2 * 1 ...

  8. etcd api 接口

    etcd api接口 基本操作api: https://github.com/coreos/etcd/blob/6acb3d67fbe131b3b2d5d010e00ec80182be4628/Doc ...

  9. Spark学习笔记之SparkRDD

    Spark学习笔记之SparkRDD 一.   基本概念 RDD(resilient distributed datasets)弹性分布式数据集. 来自于两方面 ①   内存集合和外部存储系统 ②   ...

  10. ToolStrip控件在窗体没有焦点的情况下,需要单击二次才能够激发事件的解决办法

    protected override void WndProc(ref Message m) { if (m.Msg == 0x210) { Control control = Control.Fro ...