`
huaye2007
  • 浏览: 37045 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

socket 与 mina 交互数据

阅读更多

之前网上查了些资料,有些blog说mina做服务端,socket做客户端,没法用DemuxingProtocolCodecFactory,只能用TextLineCodecFactory协议解析,但要是传文件,这个东东根本就没用,事实上,服务器很大可能是要传文件的,mina做服务端,客户端可能是不同的。比如用mina的客户端写,用nio自己写,用socket自己写,用C语言自己写。

本次测试例子:使用socket传送较长字符串,如果传送文件,也是一样的过程,先将字符串或者文件转换成byte数组

其实如果理解mina的协议解析的话就会非常简单处理这些解码:

大体思想:协议一般有头信息 告诉程序需要读取多少字节,程序就可以不断读取了,知道在哪个字节时候就不用再往后读了。

IoBuffer读取的时候就像一个管道,读取了这部分数据,这部分数据就没有,其实IO流就是这样

Socket客户端:

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.Charset;

import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;


public class client {
	

	
	public static void main(String[] args) throws Exception{
		Socket socket = new Socket("127.0.0.1",9123);
		OutputStream os = socket.getOutputStream();
		String str = "";
		for(int i=0;i<100;i++){
			str = str + "我们都是中国人啊!";
		}
		byte[] bytes = str.getBytes("utf-8");
		System.out.println("数据byte长度:"+bytes.length);
		os.write(i2b(bytes.length));
		os.write(bytes);
		os.flush();

		InputStream is = null;
		
		is = socket.getInputStream();
		byte[] intByte = new byte[4];
		is.read(intByte);
		int msgLength = b2i(intByte);
		System.out.println("int:"+msgLength);
		int readPosition = 0;
		byte[] byteArray = new byte[msgLength];
		while(readPosition < msgLength){
			int value = is.read(byteArray, readPosition, msgLength-readPosition);
			if(value == -1){
				break;
			}
			readPosition += value;
			
		}
		System.out.println(new String(byteArray,"utf-8"));
		System.out.println("byteArray Length:"+byteArray.length+" string Length:"+new String(byteArray,"utf-8").length());
		if(os != null){
			os.close();
		}
		if(is != null){
			is.close();
		}
	}
	
	// 网上抄来的,将 int 转成字节
	public static byte[] i2b(int i) {
	return new byte[] { (byte) ((i >> 24) & 0xFF),
	(byte) ((i >> 16) & 0xFF), (byte) ((i >> 8) & 0xFF),
	(byte) (i & 0xFF) };
	}
	
	public static int b2i(byte[] b) {
		int value = 0;
		for (int i = 0; i < 4; i++) {
		int shift = (4 - 1 - i) * 8;
		value += (b[i] & 0x000000FF) << shift;
		}
		return value;
	}

}
socket先发送测试数据,然后接收服务端返回的数据

package com.test;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;

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 org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;



public class BaseMessageDecoder  implements MessageDecoder {
	AttributeKey CONTEXT = new AttributeKey(getClass(),"context");
	/**
	 * 是否适合解码
	 * */
	public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
		
		// TODO Auto-generated method stub
	
		return MessageDecoderResult.OK;
	}

	/**
	 * 数据解码
	 * */
	public MessageDecoderResult decode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput outPut) throws Exception {
		// TODO Auto-generated method stub
		Context context = (Context) session.getAttribute(CONTEXT);
		// TODO Auto-generated method stub
			IoBuffer buffer = in;
			if(context == null || !context.init){
				IoBuffer b = buffer.get(new byte[4]);
				byte[] intByte = b.array();
				int num = b2i(intByte);
				System.out.println("长度:"+num);
				context = new Context();
				context.number = num;
				context.position = 0;
				context.byteArray = new byte[num];
				context.init = true;
				while(buffer.hasRemaining()){
					byte c = buffer.get();
					context.byteArray[context.position] = c;
					context.position++;
				}
			}else{
				while(buffer.hasRemaining()){
					byte c = buffer.get();
					context.byteArray[context.position] = c;
					if( context.position == context.number-1){
						System.out.println(new String(context.byteArray,"utf-8"));
						IoBuffer buff = IoBuffer.allocate(1024).setAutoExpand(true);
						buff.put(i2b(context.number));
						buff.put(context.byteArray);
						buff.flip();
						outPut.write(buff);
						return MessageDecoderResult.OK;
					}
					context.position++;
				}
			}
			session.setAttribute(CONTEXT,context);
			return MessageDecoderResult.NEED_DATA;
	}

	/**
	 * 解码完成
	 * */
	public void finishDecode(IoSession session, ProtocolDecoderOutput outPut)
			throws Exception {
		// TODO Auto-generated method stub
	}
	public static int b2i(byte[] b) {
		int value = 0;
		for (int i = 0; i < 4; i++) {
		int shift = (4 - 1 - i) * 8;
		value += (b[i] & 0x000000FF) << shift;
		}
		return value;
		}
	public static byte[] i2b(int i) {
		return new byte[] { (byte) ((i >> 24) & 0xFF),
		(byte) ((i >> 16) & 0xFF), (byte) ((i >> 8) & 0xFF),
		(byte) (i & 0xFF) };
		}
	class Context {
		public  Integer number;
		public byte[] byteArray;
		public Integer position;
		public boolean init;
	}
}
因传送字符串较长,执行多次调用decode方法,需要中间变量记住之前的部分字段值。

IoBuffer buff = IoBuffer.allocate(1024).setAutoExpand(true);
buff.put(i2b(context.number));
buff.put(context.byteArray);
buff.flip();
outPut.write(buff);

这段代码本应该写在BaseMessageEncoder的encode方法中,但出于我并没有在服务端需要这些字符串值,所以直接将数据方法IoBuffer,服务端直接写回客户端

测试数据OK。

源代码


分享到:
评论
1 楼 mixaceh 2014-07-04  

相关推荐

Global site tag (gtag.js) - Google Analytics