您的位置:首页 > 其它

Mina学习笔记 简单EchoServer(二) 编码解码修改

2015-05-29 17:51 381 查看
上一节实现了简单的EchoServer,客户端说什么,服务器返回you say:什么,但它是怎么传输的呢,协议是什么格式的呢,业务逻辑和协议真的分得很开呢



它的编码解码在这里设置

acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(
注:自己实现个ProtocolCodecFactory和ProtocolEncoder和ProtocolDecoder,然后修改上面的设置.

至于格式,简单

byte数组,变长\r\n(2个字节)

接下来,我们要传输什么对象呢,java.lang.String对象? 不太好,还是封装一下吧
<span style="font-size:14px;">package com.skymr.mina.tcptest;

public class LineText {

private String text;

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}

public String toString(){
return text;
}
}</span><span style="font-size: 16px;">
</span>


传输LineText对象,也没做什么事,只是将String包装下.

然后就要进行编码解码的代码编写了.

编码要实现ProtocolEncoder

package com.skymr.mina.tcptest;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

public class MyLineCodecEncoder implements ProtocolEncoder{

@Override
public void encode(IoSession session, Object message,
ProtocolEncoderOutput out) throws Exception {
LineText text = (LineText)message;
IoBuffer buffer = IoBuffer.allocate(1024, false);
buffer.put(text.getText().getBytes("UTF-8"));
buffer.flip();
out.write(buffer);
}

@Override
public void dispose(IoSession session) throws Exception {

}

}


编码的工作:
1)取得要编码的对象LineText
2)将LineText中的字符串对象写入到IoBuffer中
3)IoBuffer转换为读模式,写入到ProtocolEncoderOutput对象

再来看解码的实现:
package com.skymr.mina.tcptest;

import java.nio.ByteBuffer;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

public class MyLineCodecDecoder implements ProtocolDecoder{

private String key = "textKey1234";

@Override
public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
throws Exception {
ByteBuffer buffer = null;
Object o = session.getAttribute(key);
if(o == null){
buffer = ByteBuffer.allocate(1024);
session.setAttribute(key, buffer);
}
else{
buffer = (ByteBuffer)o;
}
if(in.limit()==2){
byte b1 = in.get();
byte b2 = in.get();
if(b1 == 13 && b2 == 10){
String text = new String(readBuffer(buffer));
LineText lineText = new LineText();
lineText.setText(text);
out.write(lineText);
buffer.clear();
}
}
else if(in.limit()==1){
buffer.put(in.get());
}
}
public static byte[] readBuffer(ByteBuffer buffer){
buffer.flip();
int len = buffer.limit() - buffer.position();
byte[] ret = new byte[len];
System.arraycopy(buffer.array(), 0, ret, 0, len);
return ret;
}
@Override
public void finishDecode(IoSession session, ProtocolDecoderOutput out)
throws Exception {
session.removeAttribute(key);
}

@Override
public void dispose(IoSession session) throws Exception {
session.removeAttribute(key);
}

}


每次调用decode方法时,只会收到一个字节的Buffer或者2个字节的\r\n, 没有想到会是这样的,这和Blocking IO有点像,每次传输的是1个字节,那怎么组装成一行呢,我们可以用一个缓冲区,当是一个字节传入时,放到缓冲区,当\r\n传入时,才将缓冲区写入到解码流中.有人会问,怎么保存这个缓冲区呢?作为属性变量吗,不可以,如果是只有一个客户端就没有问题,当接入了多个客户端时,数据就会混乱了,所有客户端的数据都放到了一个缓冲区,还不出错?可以用IoSession来保存,这和java Web中保存客户数据很像啊.
记得在客户端关闭时删除保存缓冲区的状态啊,否则....不知道会不会内存溢出,但保险起见吧

接下来实现ProtocolCodecFactory
package com.skymr.mina.tcptest;

import java.nio.charset.Charset;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;

public class MyLineCodecFactory implements ProtocolCodecFactory{

private ProtocolEncoder encoder = new MyLineCodecEncoder();
private ProtocolDecoder decoder = new MyLineCodecDecoder();

public MyLineCodecFactory(){

}
public MyLineCodecFactory(Charset charset){

}

@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}

@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}

}


这里没有什么可说的吧

最后修改Handler

package com.skymr.mina.tcptest;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;

public class EchoHandler extends IoHandlerAdapter{

@Override
public void sessionOpened(IoSession session) throws Exception {
System.out.println("sessionOpened");
LineText lt = new LineText();
lt.setText("please say something:\r\n");
session.write(lt);
super.sessionOpened(session);
}

@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
if("%quit%".equals(message)){
System.out.println("收到退出消息");
session.write("You will exit soon.\r\n");
session.close(true);
return;
}
System.out.println("收到消息:"+message);
LineText lt = new LineText();
lt.setText("you say:"+message+"\r\n");
session.write(lt);
}

}
没啥牛拜的, 将String换成LineText发送而已
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: