基于Mina开发网络通信程序,在传感器数据接入领域应用的很广泛,今天我无意中发现一个问题,那就是我在前端session.write(msg)数据出去之后,却没有经过Filter的Encoder方法,同样能够写入远程服务器。因为我所发送的数据不需要很复杂的编码,所以encoder方法也一直没有去看,今天发现无法被自己写的过滤器所编码,针对这个问题,我打开以前的代码以及以前的项目中的相关代码,有些同事也是session.write(IoBuffer)之后,在encoder方法里面还加上了一句out.write(message);通过跟踪Mina源码发现,session写出去的数据类型是IoBuffer格式的,就不经过自定义的过滤器了。所以下面的代码压根是多余的
@Override
public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
out.write(message);//IoBuffer格式写出去之后,跳过了encoder.
}
下面我把自己跟踪调试Mina的过程记录下来.
一、场景
客户端需要每隔Time时间向服务端发送心跳包,代码如下:
session.write(IoBuffer.wrap("心跳包XXX".getBytes()));
二、现象
MyFilter中的Encoder方法encoder不执行
public class MyFilter implements ProtocolCodecFactory {
private ProtocolEncoder encoder = new MyEncoder();
private ProtocolDecoder decoder = new MyDecoder();
@Override
public ProtocolEncoder getEncoder(IoSession session) throws Exception {
return encoder;
}
@Override
public ProtocolDecoder getDecoder(IoSession session) throws Exception {
return decoder;
}
}
三、分析
进入session.write方法,实现IoSession.write方法的是AbstractIoSession。直接调用的是
public WriteFuture write(Object message) {
return write(message, null);
}
而AbstractIoSession.write(Object message, SocketAddress address)
该方法的工作流程是:
- 创建WriteFeature对象,用于返回值(session.write本身就是返回writeFeature)
- 将session.write(message)中的Object类型的message封装成writeRequest.
- 启动write动作,这个主要是IoFilterChain来完成的。
具体的核心代码如下:
// Now, we can write the message. First, create a future
WriteFuture writeFuture = new DefaultWriteFuture(this);
WriteRequest writeRequest = new DefaultWriteRequest(message, writeFuture, remoteAddress);
// Then, get the chain and inject the WriteRequest into it
IoFilterChain filterChain = getFilterChain();
filterChain.fireFilterWrite(writeRequest);
继续跟踪到fireFilterWrite里面去,可知IoFilterChain的默认实现类DefaultIoFilterChain中的关键方法:
public void fireFilterWrite(WriteRequest writeRequest) {
Entry tail = this.tail;
callPreviousFilterWrite(tail, session, writeRequest);
}
在这里先要介绍一下DefaultIoFiterChain的数据格式,主要的属性如下:
private final Map<String, Entry> name2entry = new ConcurrentHashMap<String, Entry>();
/** The chain head */
private final EntryImpl head;
/** The chain tail */
private final EntryImpl tail;
其中 head与tail都是DefaultIoFilterChain固有的属性,name2entity是我们为FilterChain添加的过滤器。因而IoFilterChain是用一个链表来保存过滤器的(('tail', prev: 'myFilter:ProtocolCodecFilter', next: 'null')),其中表头和表位都是固定的head和tail,他们对应的Filter也是专有的,HeadFilter和TailFilter.
关键方法是callPreviousFilterWrite(tail, session, writeRequest);
try {
IoFilter filter = entry.getFilter();
NextFilter nextFilter = entry.getNextFilter();
filter.filterWrite(nextFilter, session, writeRequest);
} catch (Throwable e) {
writeRequest.getFuture().setException(e);
fireExceptionCaught(e);
}
从上面两个代码片段中,可以看出,IoFilterChain首先从列表中找到tail,从tail开始查找filter,顺序调用每个filter的filterWrite()方法。这里的‘顺序调用’,指的是从tail->head调用,也就是逆向调用Filter。但是看到filter.filterWrite(nextFilter, session, writeRequest);这行代码中的参数可以发现,nextFilter,表面的意思是下一个过滤器,有点误解,感觉tail下一个过滤器不就是null吗,其实不然,进入filterWriter可知。
Entry nextEntry = EntryImpl.this.prevEntry;
callPreviousFilterWrite(nextEntry, session, writeRequest);
对于除head和tail过滤器外,其他的过滤器是如何工作的呢?我们看看ProtocolCodecFilter中的fireFilter方法,做了这样的处理:
if ((message instanceof IoBuffer) || (message instanceof FileRegion)) {
nextFilter.filterWrite(session, writeRequest);
return;
}
到这里,就明白了为什么session.write(IoBuffer.wrap())这样写出去,无法经过自己定义的过滤器了,原来在fireFilter中,对message做了判断,如果已经是IoBuffer类型的,就直接return了。
最后执行的是HeadFilter的fireFilter方法,直接看内容:
if (writeRequest.getMessage() instanceof IoBuffer) {
IoBuffer buffer = (IoBuffer) writeRequest.getMessage();
// I/O processor implementation will call buffer.reset()
// it after the write operation is finished, because
// the buffer will be specified with messageSent event.
buffer.mark();
int remaining = buffer.remaining();
if (remaining == 0) {
// Zero-sized buffer means the internal message
// delimiter.
s.increaseScheduledWriteMessages();
} else {
s.increaseScheduledWriteBytes(remaining);
}
} else {
s.increaseScheduledWriteMessages();
}
s.getWriteRequestQueue().offer(s, writeRequest);
if (!s.isWriteSuspended()) {
s.getProcessor().flush(s);
}
WriteRequestQueue的默认实现就是java.util.concurrent.ConcurrentLinkedQueue,舍去传入的session对象。
分享到:
相关推荐
mina-core-2.0.0-M6.jar mina-example-2.0.0-M6.jar mina-filter-codec-netty-2.0.0-M6.jar mina-filter-compression-2.0.0-M6.jar mina-integration-beans-2.0.0-M6.jar mina-integration-jmx-2.0.0-M6.jar mina-...
用libltkjava-10.34.0.0.jar 编译通过了,先上传这里,让大家少费点时间,使用android studio 3.0编译的,包含jdom-1.1.3.jar libltkjava-10.34.0.0.jar log4j-1.2.17.jar mina-core-2.0.6.jar org.apache.xerces-...
apache-mina-2.0.16.zip"可能是两个不同类型的压缩包。"apache-mina-2.0.16-bin.zip"通常包含了编译好的二进制库,比如JAR文件,以及可能的运行时依赖和配置文件,适合于那些不需要源码,只需要使用Mina进行开发的...
android 上的ftp服务器例子,通过ApacheFtpServer实现,依赖以下jar包: commons-...太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
gcc-arm-11.2-2022.02-mingw-w64-i686-arm-none-eabi.exe
mina-core-2.0.0-M1.jar/mina-example-1.0.5.jar/slf4j-jdk14-1.6.1.jar/slf4j-log4j12-1.6.1.jar mina 所用jar
mina-core-1.1.7.jar minlog-1.2.jar netty-3.2.5.Final.jar objenesis-1.2.jar objenesis-2.1.jar oro-2.0.8.jar plexus-archiver-1.0-alpha-7.jar plexus-archiver-2.3.jar plexus-classworlds-1.2-alpha-7.jar ...
mina-core-1.1.7-sources.jar mina-filter-compression-1.1.7-sources.jar mina-filter-ssl-1.1.7-sources.jar mina-filter-ssl.jar slf4j-api-1.5.8-sources.jar slf4j-log4j12-1.5.8-sources.jar Openfire3.10...
hive 开发UDF 使用maven工程 引发jar包缺失 hive 开发UDF 使用maven工程 引发jar包缺失
Apache MINA是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。 当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版...
1.1.jar,log4j-1.2.14.jar,mina-core-2.0.7.jar,mssqlserver2.jar,msv-core-2011.1.jar,neethi-3.0.2.jar,oauth-20100527.jar,oauth-provider-20100527.jar,opensaml-2.5.1-1.jar,openws-1.4.2-1.jar,...
mina-filter-compression-2.0.7.jar,mina 过滤器jar包,核心包之一
apache-mina-2.0.7-bin.zip,apache-mina-2.0.7-src.zip,log4j-1.2.17.zip,slf4j-api-1.6.6.jar,slf4j-api-1.6.6-sources.jar,slf4j-log4j12-1.6.6.jar,mina-example-2.0.7.jar,mina-example-2.0.7-sources....
简单的Mina Server用到的三个jar包,官网的资料可以...http://mina.apache.org/mina-project/quick-start-guide.html qndroid老师的视频基础跳过了,加了这三个包服务端是没报错了 https://www.imooc.com/video/12197
在这个场景中,我们关注的是MINA的核心组件以及两个特定的过滤器和传输组件:`mina-core-2.0.0-RC1.jar`、`mina-filter-compression-2.0.0-RC1.jar`和`mina-transport-apr-2.0.0-RC1.jar`。 **MINA Core (mina-core...
Netty、Mina、Cindy都是不错的NIO开源框架,后两者都是在Netty的基础上演化出来的。所以要学习好Java的异步通信框架,这三个都是不可多得的好材料。 本资源仅供学习和参考使用,若要进行开发,请下载相应的Jar包。
在本案例中,我们关注的是 "mina-core-2.0.1.jar",这是 Apache MINA 的核心库,包含了框架的基本组件和功能。 **MINA 核心组件:** 1. **IoSession**:MINA 中的核心概念,它代表了服务端与客户端之间的一个连接。...
最新的 mina相关jar包 合集,里边有apache-mina-2.0.7-bin.zip,apache-mina-2.0.7-src.zip,log4j-1.2.17.zip,slf4j-api-1.6.6.jar,slf4j-api-1.6.6-sources.jar,slf4j-log4j12-1.6.6.jar,mina-example-2.0.7....
不同于0.9的版本,asyncweb2.0的版本已经可以支持最新的mina2.x。使用非常简单,仅仅需要实现一个HttpService 即可。 public interface HttpService { void handleRequest( HttpServiceContext context ) throws ...
1. `mina-core`: MINA的核心库,提供了网络通信的基本构建块,如Buffer、Filter、Session和IoHandler等。 2. `mina-filter-ssl`: 提供了SSL/TLS加密支持,用于安全的网络通信。 3. `mina-filter-codec`: 包含了各种...