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

4 篇文章 0 订阅
1 篇文章 0 订阅

上一节实现了简单的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发送而已



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值