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) 占用的是内存空 ...
随机推荐
- mysql 连接空闲超8小时自动断开连接问题(linux)
在mysql配置文件里添加wait_timeout和interactive_timeout两个值 [mysqld] wait_timeout= interactive_timeout= 超时时间,10 ...
- JS学习知我见(常用建站代码)
<!doctype html><html><head><meta charset="utf-8"><meta name=&qu ...
- Lua 5.2 编译 For Windows
body { font-family: 微软雅黑; font-size: 11pt; line-height: 1.5; } html, body { color: #000000; backgrou ...
- SSDP
SSDP:Simple Service Discover Protocol,简单服务发现协议,PC机只要网口UP,就会通过该协议寻找可用的网络服务.PC机发出的报文基于UDP协议的1900端口发送组播 ...
- --- shell 扩展的顺序
1. 扩展(expansion)是bash 解释器的重要的概念: 2. 命令替换是扩展里面的一种 3. 基本结构是: “字符串准备(花括号,波浪线,参数和变量扩展,命令替换),单词分割,路径扩展” h ...
- Oracle中SYS_CONNECT_BY_PATH函数的使用
在Oracle中,SYS_CONNECT_BY_PATH函数主要作用是可以把一个父节点下的所有子节点通过某个字符进行区分,然后连接在一个列中显示. sys_connect_by_path(字段名, 2 ...
- PHP实现队列及队列原理
看看各语言实现队列的方法:PHP实现队列:第一个元素作为队头,最后一个元素作为队尾 <?php /** * 队列就是这么简单 * * @link http://www.phpddt.com */ ...
- 1.1. 如何使用XproerUI库
项目类型:MFC XproerUI结构: 3rd 第三方库目录 cximage dll 编译的DLL目录 pug ...
- SDF文件的用途
标准延迟格式(英语:Standard Delay Format, SDF)是电气电子工程师学会关于集成电路设计中时序描述的标准表达格式.在整个设计流程中,标准延迟格式有着重要的应用,例如静态时序分析和 ...
- Comet4J推技术在SSHE三大框架中应用-linux下亲测可用
Comet4J(Comet for Java)是一个纯粹基于AJAX(XMLHTTPRequest)的服务器推送框架,消息以JSON方式传递,具备长轮询.长连接.自动选择三种工作模式. 下载地址 co ...