为什么使用协议解码过滤器 ProtocolCodecFilter ?
1) TCP保证所有的包以正确是顺序传递,但不保证发送方的一次写操作在接收方产生一次读操作。在 MINA 的术语中:没有 ProtocolCodecFilter ,发送方的一次 IoSession.write(Object message) 导致接收方多次 messageReceived(IoSession session, Object message) 事件,多次调用 IoSession.write(Object message) 可以导致单一的 messageReceived 事件。当服务器和客户端在同一台主机(或同一局域网)时,你可能不会遇到这种行为。但你的应用程序可能会遇到。
2) 大多数应用程序需要一种方法来找出当前消息的结束位置和下一个消息的开始位置。
你可以在IoHandler 里实现这些逻辑,但添加一个 ProtocolCodecFilter 可以使你的代码更加清晰和易于维护。它允许你分离协议逻辑和业务逻辑( IoHandler )。
应用程序基本上是接收一串字节,需要转换这些字节到消息(高层对象)。
有三种常用的技术来分割字节流到消息:
1、使用定长消息
2、使用固定长度的头来指示内容体长度
3、使用分隔符。
这里使用分割符(换行)来编写时间服务器的解码器。
时间服务器的请求对象为java.lang.String,对应的协议解码器为:
org.apache.mina.filter.codec.textline.TextLineEncoder和org.apache.mina.filter.codec.textline.TextLineDecoder。
响应对象定义如下:
public class TimeResponse {
private String client; // 客户端发送到字符串
private Date date;
public TimeResponse(String client, Date date) {
this.client = client;
this.date = date;
}
public String getClient() {
return client;
}
public Date getDate() {
return date;
}
}
下面是响应的编码器:
public class TimeResponseEncoder extends ProtocolEncoderAdapter {
@Override
public void encode(IoSession session, Object message,
ProtocolEncoderOutput out) throws Exception {
TimeResponse res = (TimeResponse) message;
IoBuffer buff = IoBuffer.allocate(32);
buff.setAutoExpand(true);
buff.setAutoShrink(true);
CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
buff.putString(res.getClient() + " 您好!服务器时间是:", encoder);
Date date = res.getDate();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd,HH时mm分ss秒");
buff.putString(sdf.format(date), encoder);
buff.put((byte)'\n');
buff.flip();
out.write(buff);
out.flush();
System.err.println("res encode end .... ");
}
}
业务处理器通过IoSession.write()写出的都是响应对象,所以这里可以直接进行强类型转换
TimeResponse res = (TimeResponse) message;
编码后的内容是写到 ProtocolEncoderOutput out,传给下一个过滤器。
然后是响应的解码器:
public class TimeResponseDecoder extends CumulativeProtocolDecoder {
@Override
protected boolean doDecode(IoSession session, IoBuffer in,
ProtocolDecoderOutput out) throws Exception {
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
int start = in.position();
int end = in.remaining() - 1;
if (end >= 0 && in.get(end) == (byte) '\n') {
String res = in.getString(decoder);
out.write(res);
return true;
} else {
in.position(start);
}
return false;
}
}
解码器继承自CumulativeProtocolDecoder的好处是,当缓存的内容还不够解码为一个响应对象时,可以继续缓存响应内容,只要返回false即可。
有了请求和响应的编解码器后,定义一个解码器工厂:
public class TimeResponseCodecFactory implements ProtocolCodecFactory {
private ProtocolDecoder decoder;
private ProtocolEncoder encoder;
public TimeResponseCodecFactory(boolean server) {
if(server) {
decoder = new TextLineDecoder(Charset.forName("UTF-8"));
encoder = new TimeResponseEncoder();
} else {
decoder = new TimeResponseDecoder();
encoder = new TextLineEncoder(Charset.forName("UTF-8"));
}
}
@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}
@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
}
MINA会调用工厂的 getDecoder 和 getEncoder 方法。
注意:服务器端的解码器是请求解码器,编码器是响应编码器;客户端的解码器是响应解码器,编码器是请求编码器。
修改服务器和客户端的过滤器配置
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TimeResponseCodecFactory(true/false)));
服务器端的处理器现在可以直接写响应对象了:
public class TimeServerHandler extends IoHandlerAdapter {
private Logger log = LoggerFactory.getLogger(TimeServerHandler.class);
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String str = message.toString();
log.info("server receive :" + str);
if("quit".equalsIgnoreCase(str.trim())) {
session.close(true);
return;
}
Date date = new Date();
TimeResponse res = new TimeResponse(str, date);
session.write(res);
log.info("message writter ...");
}
}
而客户端的处理器也可以直接处理响应对象:
public class ClientHandler extends IoHandlerAdapter {
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String msg = (String) message;
System.out.println("response :" + msg);
}
}
有了协议解码过滤器,处理器就不需要考虑底层的编解码的问题,只需要处理高层的业务对象,达到了分层的目的。
转自:http://wen866595.iteye.com/blog/1154137
相关推荐
NULL 博文链接:https://wen866595.iteye.com/blog/1154137
许多刚接触mina的朋友,对于mina的编解码器的编写很迷惑.希望这个文档可以帮助朋友们少走弯路。 资源中是一个比较典型的编解码器写法。生成了可执行文件。并对编解码器的代码有详细注释。
Apache MINA是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。 当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版...
NULL 博文链接:https://thb143.iteye.com/blog/1538083
mina仿qq聊天功能,自定义协议,协议的编码和解码详解,发送xml对象json,mina开发大全,详细api mina聊天 mina解码编码 mina协议开发 mina仿qq mina消息xml mina开发的在线聊天工具,mina仿qq功能,mina自定义协议,可以...
这个代码,在mina框架中,实现了编码解码,包含了服务器端发送数据的代码和作为客户端接收数据的代码。
NULL 博文链接:https://mina-java.iteye.com/blog/1115429
本资源包含两个 pdf 文档,一...第九章:编解码器过滤器 第十章:执行者过滤器 第十一章:SSL 过滤器 第十二章:日志过滤器 第十三章:调试 第十四章:状态机 第十五章:代理 第十六章:JMX 集成 第十七章:Spring 集成
mina 协议 解包 粘包
该压缩包中有两个文件夹mina_server和minaclient,先启动mina_server,然后启动minaclient即可运行
Mina协议节点(主网,devnet) Mina存档节点 PostgreSQL数据库 边车(仅适用于主网) 项目网址: Inspired by Mina - the world's lightest blockchain | minaprotocol.com Send some candies if you found this ...
mina-filter-compression-2.0.7.jar,mina 过滤器jar包,核心包之一
mina 多路分离解码
mina通信协议文档及实例,内含说明文档及实例,长短连接
apache-mina-2.0.16.zip
minaprotocol-dev.github.io Mina协议市场
添加过滤器 16 自定义编解码器 17 制定协议的方法: 19 IoBuffer常用方法: 19 Demo1:模拟根据文本换行符编解码 20 Demo2:改进Demo1的代码 22 Demo3:自定义协议编解码 31 3.IoHandler接口 50 三. Mina实例 50 四...
公司需求,做的简单的Demo,可以拓展,Mina自定义协议简单实现,象征性得收取2积分
添加过滤器 16 自定义编解码器 17 制定协议的方法: 19 IoBuffer常用方法: 19 Demo1:模拟根据文本换行符编解码 20 Demo2:改进Demo1的代码 22 Demo3:自定义协议编解码 31 3.IoHandler接口 50 三. Mina实例 50 四...
网站使用NextJS且内容丰富 首先,请确保您已安装git lfs 。 在Mac上运行: brew install git-lfs 之后,您必须在网站目录中安装git-lfs并将其拉出。 git lfs install git lfs pull 安装并运行: ...