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) 占用的是内存空 ...
随机推荐
- MFC 响应控件消息
第一种,消息映射 第二种,重写OnCommand BOOL CmfcdlgDlg::OnCommand(WPARAM wParam, LPARAM lParam){ switch(wParam) { ...
- 配置Struts.xml DTD文件报错
报错信息为: The content of element type "struts" must match "((package|include|bean| cons ...
- archlinux配置答疑
Q: chinese can not appear in my firefox and terminal rightly A: pacman -S wqy-microhei Q: install pi ...
- 用CMake构建Qt5的Visual Studio工程
使用Visual Studio构建Qt工程的方法有很多种,可以使用Visual Studio自带的功能手动创建配置工程,也可以创建pro文件,然后通过VS的Qt插件导入进行创建.还有一种方式是通过CM ...
- heartbeat重要文件的配置参数说明
主要三个重要的文件:ha.cf, authkey, haresource 1)ha.cf的重要参数的说明: 参数 说明 debugfile /var/log/ha-debug h ...
- MongoDB的基础知识
本人只是软件开发的一个菜鸟,在学习MongoDB,总结了一点自己学习的知识,监督自己学习. 如果文章中有不足的地方,还请大神指点迷津,纠正改错,谢谢. 一.MongoDB简介 MongoDB是一个基于 ...
- jquery ajax 前前后后,所有的函数并查询链接
jQuery Ajax 操作函数 jQuery 库拥有完整的 Ajax 兼容套件.其中的函数和方法允许我们在不刷新浏览器的情况下从服务器加载数据. 函数 描述 jQuery.ajax() 执行异步 H ...
- Oracle数据库like和not like使用
查询手机号注册的记录而不是邮箱 查询2开头的记录 select * from beyond_pay_offline where amount like '2%'
- Google V8编程详解(一)V8的编译安装(Ubuntu)
V8的编译比较简单,需要同时安装git和svn. 下载V8源码: git clone git://github.com/v8/v8.git v8 && cd v8 切换到最新版本: g ...
- PHP面向对象_重载新的方法(parent::)
在学习PHP 这种语言中你会发现, PHP中的方法是不能重载的, 所谓的方法重载就是定义相同的方法名,通过“参数的个数“不同或“参数的类型“不 同,来访问我们的相同方法名的不同方法.但是因为PHP是弱 ...