• 使用 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;
    	}
    }


  • 相关阅读:
    【Codeforces Round #432 (Div. 1) B】Arpa and a list of numbers
    【Codeforces Round #433 (Div. 1) B】Jury Meeting
    【 2017 Multi-University Training Contest
    【Codeforces Round #433 (Div. 2) C】Planning
    JavaEE(15)
    谓词推入引发的惨案
    子查询解嵌套in改写为exists
    子查询解嵌套not in 无法展开改写
    dump datafile block
    关于v$sql_bind_capture 的问题
  • 原文地址:https://www.cnblogs.com/java20130723/p/3212029.html
Copyright © 2020-2023  润新知