Cindy中的Filter
Cindy中的Filter
- 类似于MINA的方式,在Listener的相应接口中加入下一个Listener对象。
比如假设原来是public void sessionEstablished(Session session)的声明,那么现在可以改为public void sessionEstablished(Session session, NextSessionListener nextListener)。用户需要在其实现类中手动调用下一个Listener来处理。
这种方法基本被我否认,一来所有的现有实现都需要变化,没办法兼容;二来出错的可能性比较大,用户应该调用 nextListener.sessionEstablished(session),可万一用户敲成了 nextListener.sessionClosed(session)就能导致意外的出错。(我认为这个很容易发生,因为next...的这种代码肯 定会在SessionListener中出现多次,用户很有可能就复制粘贴了,拷贝完忘了改是很有可能的)
- 通过一FilterListener类来实现过滤,该Filter类也实现SessionListener接口,如同MessageRecognizerChain类;并且提供额外的Filter接口,通过该类的addFilter方法来添加Filter实例
如下伪码也许可以表达出该含义:
SessionFilterListener filter = new SessionFilterListener();
session.addSessonListener(filter);
filter.addFilter(some filterA);
filter.addFilter(some filterB);
感觉上还是和原来的代码不太兼容
- 单独的Filter接口,和SessionListener接口不相关;框架内部提供一个默认Filter实现
比如:
public interface SessionFilter {
public boolean filter();
}
public class DefaultSessionFilter implements SessionFilter {
public boolean filter() {
return true; //默认永远交给下一个Filter处理,这样和原来的Iterator模型相同
}
}
public class XXXSession implements Session {
public void addSessionListener(SessionListener listener) {
if (listener instanceof SessionFilter)
listeners.addListener(listener);
else
listeners.addListener(new DefaultSessionFilter(listener));
}
}
这样只在添加的时候通过instanceof检测了一次,迭代的时候就都转换为SessionFilter和SessionListener接口来处理,不再需要额外的判断,并且完全兼容Cindy以前的版本。
另外,用户如果要改变其行为,也不容易出错了,如:
public class CustomSessionListener implements SessionListener, SessionFilter {
public boolean filter() {
return isLogon();
}
}
我是比较倾向于第三种方案的。
昨晚写完这篇就回家了,在路上突然想到了第三种方式的缺陷。第一是比较难以复用 SessionListener,比如若干个Session共享一个SessionListener时,这种方式会有问题;第二是多线程时两次方法调用可 能会产生同步的问题,系统内部肯定要先调用SessionListener的相应方法,然后再调用filter方法,在单线程问题下可能不会出现什么问 题,但多线程状况下就会出现问题。
是否要回到最简单的方式呢?或者干脆就是分离Filter和Listener机制?
Cindy中的Filter(二)
Cindy中的Filter(三)
void sessionClosed(Session, SessionFilterChain) throws Exception;
void messageReceived(Session, SessionFilterChain) throws Exception;
......
void dataReceived(Session, SessionFilterChain, ByteBuffer) throws Exception;
void dataSent(Session, SessionFilterChain, ByteBuffer) throws Exception;
void sendData(Session, SessionFilterChain, ByteBuffer) throws Exception;
}
boolean decode(Data); //对应以前的 boolean readFromBuffer(ByteBuffer)
Data encode(); //对应以前的 ByteBuffer[] toByteBuffer()
}
ByteBuffer getBuffer();
void setBuffer(ByteBuffer);
SocketAddress getAddress();
void setAddress(SocketAddress);
}
......
void dataReceived(Session, SessionFilterChain, Data) throws Exception;
......
}
如果再加上我原来说的MessageSource接口:
boolean hasNext();
Message next();
}
public interface Session {
void addSessionListener(SessionListener);
void addSessionFilter(SessionFilter);
......
Task start() throws ...;
Task stop() throws ...;
Task send(Message) throws ...;
Task send(MessageSource) throws ...;
}
boolean cancel();
boolean isCancelled();
boolean complete();
boolean complete(int timeout);
boolean isCompleted();
}
Socket的getInputStream实际上是一个pull的模式,即应用必须要明确通过getInputStream().read(...)来读取数据,否则当系统该连接网络输入缓冲区满了后就不会继续接收数据了。
可以用敞口的杯子来比喻Socket,getInputStream是一根放在杯中的吸管,read就是通过吸管来吸水。如果一直不吸水,则当杯子满了后,后面加入的水就会被丢弃掉。
Cindy实际上是一个push的模式,应用不需要主动来读取数据,当系统接收到数据后,cindy会主动通过SessionListener派发给应用。
可以用一个漏斗来比喻Cindy的SocketSession,SessionListener是漏斗的管子,只要加了水,则就会通过管子流到应用中去。当然,如果漏斗上部满了,则后面加入的水也会被丢弃掉。
TCP是基于流的协议,这表示对于TCP本身而言,数据是没有边界的。但是对于TCP应用而言,数据是有边界的,这要靠应用自己去识别。
举 个简单的例子,假设一串字节流00 01 02 03 04 05,TCP本身并不知道边界在哪里,可能这串字节流是分成三个包00 01、02 03、04 05收到的,也有可能是分成两个包00 01 02、03 04 05收到的,这对TCP来说没有什么区别(除开效率上的考虑外)。
甚至可以是TCP先收到04 05,再收到02 03,再收到00 01,但是TCP协议有字段标识顺序,所以接收后又重新将顺序组装成00 01 02 03 04 05了。
但是对于应用1来说,数据可能是00 01 02、03 04 05这样分组的;对于应用2来说,数据可能是00 01、02 03、04 05这样分组的,这需要应用自己来区别。
比如对于应用1来说,
public class MessageRecognizer1 implements MessageRecognizer {
public Message recognizeMessage(....) {
if (buffer.remaining >= 3) //这里做了判断
return new Message1();
return null;
}
}
对于应用2来说,
public class MessageRecognizer1 implements MessageRecognizer {
public Message recognizeMessage(....) {
if (buffer.remaining >= 2) //这里做了判断
return new Message1();
return null;
}
}
如果采用InputStream,则对于应用1来说
getInputStream().read(...); //由于是阻塞的,一定等读完了三个字节,方法调用才返回
processMessage1(...);
对于应用2来说
getInputStream().read(...); //由于是阻塞的,一定等读完了两个字节,方法调用才返回
processMessage1(...);
所以实际上所有的边界判断都是在用户的逻辑中的,而TCP本身并不负责任何数据边界逻辑的判断。
//============================================================================
reader = new XPPPacketReader();
reader.setXPPFactory(factory);
reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(),
CHARSET));
这 是我在一个实际的程序中写的程序, 用Cindy 来写的, 但我也感觉有问题, 但也的确没出什么问题, 因为Cindy 的Message 也是收到多少, 读多少, 那么这样的话应该也无法区分出消息1和消息2的啊, 注意我所说的消息是代表我所发送的一段字节流, 这个字节流是一个XML 文本, 在这个文本当中我们没有长度标识啊,所以在我看来对应用来说他们是无法区分消息1和消息2的, 但他们有偏偏不出问题, 不解, 期待Crmky 的解释, 谢谢!!
//============================================================================
tcpSession.addSocketSessionListener(new SessionAdapter() {
//接收到消息
public void messageReceived(Session session, Message message) {
ByteArrayMessage msg=(ByteArrayMessage)message;
InputStream InS = null ;
System.out.println(msg.toString());
ByteBuffer[] msgBuffer = msg.toByteBuffer();
for(int i=1 ;i<=msgBuffer.length-1;i++){
InS = newInputStream(msgBuffer[1]);
}
if (InS != null){
sPacket=forumNIOReader.readStream(InS);
sPacket=CharsetUtils.encode("utf-8",sPacket).toString();
session.write(new ByteArrayMessage(sPacket.getBytes()));
session.write(new ByteArrayMessage("/n".getBytes()));
}
}
...
...
}
...
public String readStream(InputStream InStream) {
reader = new XPPPacketReader();
reader.setXPPFactory(factory);
try {
reader.getXPPParser().setInput(new InputStreamReader (InStream,CHARSET));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (XmlPullParserException e1) {
e1.printStackTrace();
}
...
}
Cindy中的Filter相关推荐
- SpringBoot学习之路:09.Spring Boot中添加Filter应用
2019独角兽企业重金招聘Python工程师标准>>> 上篇文章中说了SpringBoot中是如何使用servlet的,本文将讲解在SpringBoot中对过滤器Filter的实现 ...
- Java Web中的Filter和Interceptor的区别
2019独角兽企业重金招聘Python工程师标准>>> 1.问题的来源 项目中使用了Filter,进行白名单的控制,同时使用了Filter进行了跨域请求的控制,使用了Intercep ...
- javaweb过滤器_JavaWeb技术(2):SpringMVC中的Filter
Filter顾名思义就是过滤器,在JavaWeb体系中,他在服务端,卡在请求/响应与Servlet之间做一些操作: 过滤器相关的类的顶层接口如下,以下方法都由Web容器自动调用: package 你可 ...
- vue 中的el表达式_Vue中vue.filter()的使用方法介绍(过滤)
本篇文章给大家带来的内容是关于Vue中vue.filter()的使用方法介绍(过滤),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. Vue过滤器 {{msg |msgFormat}} ...
- web.xml 中的filter
Servlet API的2.3版本中最重要的一个新功能就是能够为servlet和JSP页面定义过滤器.过滤器提供了某些早期服务器所支持的非标准"servlet链接"的一种功能强大且 ...
- Python3中的 Filter的改变
在python3中,filter处理之后,变成了一个可迭代对象,解决办法有2中: ① 切成python2 ② 在filter外面套一层list df = df.dropna() lines=df.co ...
- JS中 map, filter, some, every, forEach, for in, for of 用法总结
for.for in和for of和forEach的区别:http://blog.sina.com.cn/s/blog_c112a2980102xqg9.html JS中 map, filter, s ...
- 数组中的filter方法_数组filter()方法以及JavaScript中的示例
数组中的filter方法 JavaScript filter()方法 (JavaScript filter() method) filter() method is used to returns a ...
- JAVA中解决Filter过滤掉css,js,图片文件等问题
JAVA中解决Filter过滤掉css,js,图片文件等问题 参考文章: (1)JAVA中解决Filter过滤掉css,js,图片文件等问题 (2)https://www.cnblogs.com/er ...
最新文章
- spring中Validation设计与实现
- qt 中出现ld returned1exit status错误的几个原因
- 浅谈js本地图片预览
- C#下把txt文件数据读进sql server中存储所遇到的乱码问题
- 【CodeForces - 761B】Dasha and friends (思维,模拟,构造)
- React Native开发指南-在原生和React Native间通信
- DECLARE_GLOBAL_DATA_PTR
- 【算法学习】纯高斯模糊算法处理灰度图片
- cocos2d-x 3.x BabeLua 插件不能断点调试
- 聊聊如何对员工做绩效考核
- python模拟登录淘宝参数在哪获取_如何用 Python 模拟登录淘宝?
- wifi服务器端口映射,主流路由器端口映射的方法
- 笔记本电脑蓝牙设置开关消失不见的处理方法
- 交集选择器与并集选择器
- 极光Im + layIm 实现后台聊天
- golang后台管理系统Iris+Layui框架搭建教程
- 数据归一化 minmax_scale()函数解析
- java entropy_java面试
- Matlab:isempty()函数用法
- 输入一个字符,判断输入的是控制字符、数字、大小写字母还是其他字符,并给出相应提示
热门文章
- 告别2017,拥抱2018!
- 《爱你就像爱生命》读后
- 计算机 实验室安全准入制度,合肥工业大学实验室安全准入制度
- 2019北大计算机夏令营,2019年北京大学化学学院“全国优秀大学生夏令营”第三轮通知...
- 关于MII、RMII、GMII、RGMII、PHY、网络变压器、RJ45的硬件总结
- 计算机网络基础结构;对等网的特点;网络的扩大;网络的拓扑结构;
- BCD工艺、CMOS工艺、BiCMOS工艺
- java 实现http长轮询,webim使用http长轮询如何保证消息的绝对实时性
- uniapp 小程序使用腾讯地图搜索位置地点,获取省、市、县地区码的方法
- feign.codec.DecodeException异常解决方案