Mina学习笔记 简单EchoServer(二) 编码解码修改
2015-05-29 17:51
381 查看
上一节实现了简单的EchoServer,客户端说什么,服务器返回you say:什么,但它是怎么传输的呢,协议是什么格式的呢,业务逻辑和协议真的分得很开呢
它的编码解码在这里设置
注:自己实现个ProtocolCodecFactory和ProtocolEncoder和ProtocolDecoder,然后修改上面的设置.
至于格式,简单
接下来,我们要传输什么对象呢,java.lang.String对象? 不太好,还是封装一下吧
传输LineText对象,也没做什么事,只是将String包装下.
然后就要进行编码解码的代码编写了.
编码要实现ProtocolEncoder
编码的工作:
1)取得要编码的对象LineText
2)将LineText中的字符串对象写入到IoBuffer中
3)IoBuffer转换为读模式,写入到ProtocolEncoderOutput对象
再来看解码的实现:
每次调用decode方法时,只会收到一个字节的Buffer或者2个字节的\r\n, 没有想到会是这样的,这和Blocking IO有点像,每次传输的是1个字节,那怎么组装成一行呢,我们可以用一个缓冲区,当是一个字节传入时,放到缓冲区,当\r\n传入时,才将缓冲区写入到解码流中.有人会问,怎么保存这个缓冲区呢?作为属性变量吗,不可以,如果是只有一个客户端就没有问题,当接入了多个客户端时,数据就会混乱了,所有客户端的数据都放到了一个缓冲区,还不出错?可以用IoSession来保存,这和java Web中保存客户数据很像啊.
记得在客户端关闭时删除保存缓冲区的状态啊,否则....不知道会不会内存溢出,但保险起见吧
接下来实现ProtocolCodecFactory
这里没有什么可说的吧
最后修改Handler
它的编码解码在这里设置
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter( |
至于格式,简单
byte数组,变长 | \r\n(2个字节) |
<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发送而已
相关文章推荐
- SonarQube4.4+Jenkins进行代码检查实例之二
- tookit2D使用4——2d照相机的使用
- UML面向对象分析与设计试题2008-B卷
- 手工创建oracle数据库
- office 2013下载及安装方案
- SVN服务器搭建和使用(二)
- ClientScript.GetCallbackEventReference实现局部刷新
- 个人发展
- LeetCode -- Longest Substring Without Repeating Characters
- 关于Xcode6模拟器 键盘不显示和没有中文输入法的解决方案
- 环境变量不一致导致安装cassandra报错
- session案例:防止表单重复提交、一次性校验码
- 数据库操作-增删改查-多对多关系以及一对多(外键)关系
- MQ消息流中JavaCompute节点如何添加消息头(MQRFH2)属性
- const的用法
- applicationContext.xml文件放置位置
- spring嵌套事物
- BAT解密:互联网技术发展之路(4)- 存储层技术剖析
- Unity3D学习技巧
- curl 选项属性配置说明