Mina传输大数组,多路解码,粘包问题的处理
我的实际情况:
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传输大数组,多路解码,粘包问题的处理的更多相关文章
- 使用 mina 传输大字节数组
转载自:http://seara520.blog.163.com/blog/static/16812769820103214817781/ 使用mina传输超过2k以上的数据时(采用tcp方式,如果是 ...
- Socket传输简单的信息以及粘包问题的解决
一.简单的socket程序——传输简短文字: # -*- coding: utf-8 -*- # -*- Author: WangHW -*- import socket whw_client = s ...
- python网络编程-socket上传下载文件(包括md5验证,大数据发送,粘包处理)
ftp server 1) 读取文件名 2)检查文件是否存在 3)打开文件 4)检查文件大小 5)发送文件大小给客户端 6)等客户端确认 7)开始边读边(md5计算)发数据 8)给客户端发md5 ft ...
- socket编程 TCP 粘包和半包 的问题及解决办法
一般在socket处理大数据量传输的时候会产生粘包和半包问题,有的时候tcp为了提高效率会缓冲N个包后再一起发出去,这个与缓存和网络有关系. 粘包 为x.5个包 半包 为0.5个包 由于网络原因 一次 ...
- 【游戏开发】网络编程之浅谈TCP粘包、拆包问题及其解决方案
引子 现如今手游开发中网络编程是必不可少的重要一环,如果使用的是TCP协议的话,那么不可避免的就会遇见TCP粘包和拆包的问题,马三觉得haifeiWu博主的 TCP 粘包问题浅析及其解决方案 这篇博客 ...
- TCP粘包问题的解决方案01——自定义包体
粘包问题:应用层要发送数据,需要调用write函数将数据发送到套接口发送缓冲区.如果应用层数据大小大于SO_SNDBUF,那么,可能产生这样一种情况,应用层的数据一部分已经被发送了,还有一部分还在 ...
- c# socket 解决粘包,半包
处理原理: 半包:即一条消息底层分几次发送,先有个头包读取整条消息的长度,当不满足长度时,将消息临时缓存起来,直到满足长度再解码 粘包:两条完整/不完整消息粘在一起,一般是解码完上一条消息,然后再判断 ...
- TCP 粘包问题浅析及其解决方案
最近一直在做中间件相关的东西,所以接触到的各种协议比较多,总的来说有TCP,UDP,HTTP等各种网络传输协议,因此楼主想先从协议最基本的TCP粘包问题搞起,把计算机网络这部分基础夯实一下. TCP协 ...
- PYTHON-TCP 粘包
1.TCP的模板代码 收发消息的循环 通讯循环 不断的连接客户端循环 连接循环 判断 用于判断客户端异常退出(抛异常)或close(死循环) 半连接池backlog listen(5) 占用的是内存空 ...
随机推荐
- C#运算符大全_各种运算符号的概述及作用
一.[]方括号 ([]) 用于数组.索引器和属性,也可用于指针. 1.数组类型是一种后跟 [] 的类型:int[] fib = new int[100]; //创建一个有100元素的数组若要访问数组的 ...
- Bootstrap表单
Bootstrap 提供了下列类型的表单布局: 垂直表单(默认) -> 这个不好看,都是手机版了,PC版占一排不好看: 内联表单 -> 我相信这个才是你想要的,PC版响应横排,手机版响应竖 ...
- xhprof学习笔记
一.简介 XHProf 是一个轻量级的分层性能测量分析器. 在数据收集阶段,它跟踪调用次数与测量数据,展示程序动态调用的弧线图. 它在报告.后期处理阶段计算了独占的性能度量,例如运行经过的时间.CPU ...
- 解决vs2008无法切换设计视图的问题
在 Visual Studio 2008的编辑一个web页面的时候,“源视图”(Source View), 你可以自定义设计视图(Design View)为默认视图. 方法如下: 菜单:工具+选项+h ...
- 如何禁止 Mac OS X 在外接设备上生成 .DS_Store 文件?以及如何批量删除 .DS_Store 文件?
如何禁止 Mac OS X 在外接设备上生成 .DS_Store 文件?以及如何批量删除 .DS_Store 文件?原文链接:http://www.java2class.net/bbs/viewthr ...
- DAO实例代码优化
一般在接口的实现类中不用来实现登陆等功能,在测试类中实现并且测试. package com.beiwo.epet.service.impl; import com.beiwo.epet.dao.Mas ...
- 磁盘阵列(RAID)实例
raid技术分类可以分为基于软件raid技术和基于硬件raid技术 raid又分为raid-0.raid-1.raid-5和raid-10 Raid有”廉价磁盘冗余阵列”的意思,就是利用多块廉价的硬盘 ...
- Hibernate—— 一对多 和 多对多关联关系映射(xml和注解)总结(转载)
One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XML/Annotation) 懒加载和积极加载 一对多双向外键关联(XML/Annotati ...
- Python全栈开发day8
一.python生成/迭代器 yiled生成数据 python迭代器, 访问数据(通过next一次一次去取) 二.反射 通过字符串的形式,导入模块 通过字符串的形式,到模块中,寻找指定的函数,并执行 ...
- sql 2012日志文件频繁出现:svchost (4892) 数据库引擎已分离数据库(1、C:\Windows\system32\LogFiles\Sum\Current.mdb)
svchost (4892) 数据库引擎已分离数据库(1.C:\Windows\system32\LogFiles\Sum\Current.mdb).(时间=0 秒) 内部计时序列: [1] 0.00 ...