Cindy中的Filter
来源:互联网 发布:晋中干部网络培训学校 编辑:程序博客网 时间:2024/05/06 03:31
Cindy中的Filter
- 类似于MINA的方式,在Listener的相应接口中加入下一个Listener对象。
比如假设原来是public void sessionEstablished(Sessionsession)的声明,那么现在可以改为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、0203、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
- Cindy 3.0中的Buffer设计
- Cindy有感
- cindy 目标
- cindy 问答
- Cindy User Guide
- Cindy Message/MessageRecognizer interface
- cindy 重名函数
- Cindy 3.0 效率测试
- Cindy 3.0a3 released
- Cindy 3.0a2 released
- cindy Concurrent 流量控制
- Cindy 3.0a5 released
- Cindy 3.0a4 released
- Cindy 3.0a4 configuration
- Cindy 3.0b1 released
- cindy源码分析filterchain
- Cindy User Guide
- 关于C++中函数参数是省略号的应用
- Chrome OS & Google Wave
- 功能覆盖率
- const函数重载
- C#笔试题
- Cindy中的Filter
- C程序的函数在内存的布局
- 链表反转
- 感恩节
- Asp.Net的面试题
- MyEclipse7.5安装CDT以失败告终结尾了。
- perl和tcl 在验证中 (附do文件例子)
- C++字符数组表示字符串--易错标识
- Wine简介