socket 与 mina 交互数据

来源:互联网 发布:联通首选网络类型 编辑:程序博客网 时间:2024/05/26 02:55

之前网上查了些资料,有些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 stubreturn MessageDecoderResult.OK;}/** * 数据解码 * */public MessageDecoderResult decode(IoSession session, IoBuffer in,ProtocolDecoderOutput outPut) throws Exception {// TODO Auto-generated method stubContext context = (Context) session.getAttribute(CONTEXT);// TODO Auto-generated method stubIoBuffer 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。

源代码


原创粉丝点击