IoBuffer
是
MINA
中的独有接口,主要继承实现的是
java NIO
中的
ByteBuffer
,所以从使用方法上来看二者区别不大,唯一比较大的区别就是,
IoBuffer
支持可变长的数据填充,对于这个类有三个关键属性,分别是
capacity(
容量
)
:
是它所包含的元素的数量。缓冲区的容量不能为负并且不能更改。
limit(
限制
)
:
是第一个不应该读取或写入的元素的索引。
position
(
位置
)
:
是下一个要读取或写入的元素的索引。
以上三个属性的值都不能为负,其关系遵守以下不变式:
0<=
位置
<=
限制
<=
容量
在这里还要郑重的介绍三个方法分别是:
clear()
:
使缓冲区为一系列新的通道读取或相对放置
操作做好准备:它将限制设置为容量大小,将位置设置为
0
。
flip()
:
使缓冲区为一系列新的通道写入或相对获取
操作做好准备:它将限制设置为当前位置,然后将位置设置为
0
。
rewind()
:
使缓冲区为重新读取已包含的数据做好准备:它使限制保持不变,将位置设置为
0
。
从本质上讲这三个方法都是对之前所介绍的三个属性进行操作,所以这里就会有一个误区,很多人从字面上解读
clear()
这个方法,以为这个方法就是将数据擦除。而实际上
clear
方法并不有擦除数据,仅仅是做了二件事,一是将
limit=capacity,
二是
position=0
,这使得数据好像被清除,以便接收下一次的读写。但请大家千万注意
,在写自定义解(编)码器时一定不要随便使用这些方法,请确保在对这些方法有了足够的认识后(最好的方法就是解读源码),才去使用它。特别是直接使用
clear()
时,一旦使用不当,在截取数据非常容易发生死循环的情况,因为前面已经说过,
clear
并不是清除数据,而只是改变属性值,也就是说原数据依旧保留,这会导致某些时候会不停的重置这三个属性,去读同一段索引的数据,从而导致死循环。网上好多
demo
都是直接使用的
clear()
,其实都是存在一定隐患的,希望能看到这里的朋友能引起警惕
,
个人认为最好的清除方式就是人为的控制
Iobuffer
的三个属性值。
以下是参考代码
:
int
oldPos = in.position();
int
oldLimit = in.limit();
.......
开始
..........
处理数据
.......
结束
..........
int
pos = in.position();
in.limit(oldLimit);
in.position(pos);
注:
以上代码仅适用于一次读取不完,需要从iobuffer
中多次读取的情况,具体情况请具体对待,核心思想就是操作iobuffer
的三个属性。
这个方法的作用,只要是用过
socket
编程的童鞋都知道它的作用。没错,它就是通过发送一个紧急字符到服务端
(对
socket
来说实际上并不存在严格意义上的客户端或服务端,谁主动谁就是客户端)
,用来测试连接是否保持的一个方法。使用这个方法有二个限制。一是必须对方的
OS
支持该方法,二是要求服务端的
SO_OOBINLINE
为
false.
否则
服务
端将会把这个紧急字符认为是正常报文一并接收,而不是抛弃。反之当
SO_OOBINLINE
为
true
时,这个紧急字符仅仅用来确认通讯是否正常之用,服务端接收后会立刻抛弃不予处理的。默认情况下
SO_OOBINLINE
的值就是
false,
所以一般情况下,客户端直接用这个方法就可以测试连接是否保持了。
按理来说这个默认设置是个好事,但在笔者的项目开发中曾经因为这个
sendUrgentData
()
被困扰了近一周的时间。事情的起因要从性能测试开始说起。
测试人员在测试过程中发现当前置机启动后有连接产生时就会让
CPU
占用率高居不下,开始笔者不是很在意,认为这个时间里有
IO
操作,
CPU
高居不下很正常,后来进一步测试发生在没有数据发送的情况下
CPU
也会占到近
50%
左右,这个现象就很不正常了,于是折腾开始。
先是确认前置机的哪个部分会占用
cpu,
很快将目标锁定到了调度机,接下来对调度机进行代码排查,没有发生任何问题,头大了,再次进入
QQ
群讨论该问题,有人向我推荐了
JRMC
(这也是我要向大家强烈推荐该工具的原因,网络的力量是强大的!!!嘿嘿。。。),通过这个监视工具,本人很快就再次缩小目标,将目标定位到一个叫
Ioprocesse-1
的线程上面,从名字及本文之前介绍的内容来看,很明显这个
MINA
框架内部线程导致的,随后就到网上查找是否有同类的现象,很遗憾本人可能是遇到一个前所未有的问题了,网络上提到使用
MINA
导致
CPU
占用率过高的内容几乎没有,无奈之下本人试着换
JDK
版本、
MINA
版本、甚至改写
MINA
源代码,一番折腾下来,结果是统统做了无用功。因为这个问题暂时不会影响测试和使用再加上时间过紧,后来就暂时将这个问题搁置了起来。某天,在开发的过程中笔者忽然想到:前置机的三个部分都是独立程序,通信机的接口也都是用
mina
改写的,为什么终端与通讯机没有这种现象发生呢?一番推理之下,本人反而将目标锁定到了占用率正常的通机机上面了,通过反复的排查,最终将问题锁定到了方法级,那就是
sendUrgentData
这个罪魁祸首。
本人试验发现,只要没有调用
sendUrgentData
方法所有一切都很正常,
但通信机
一旦调用
sendUrgentData
方法用来测试与调度机是否保持通信时,就会让调度机的
CPU
占用率瞬间飙升。但一个通信程序测试连接的方法是必不可少,而且暂时没有更好的能代替
sendUrgentData
的方法,所以就想着去改造
sendUrgentData
的源代码,结果一番跟踪下来才傻了眼,原来
sendUrgentData
方法
的底层实现是
native
类型(
注三
)根本就无从改起,最终本人将注意打到了调度机的解码器上面。代码比较多笔者就不帖了,只写上具体的解决步骤,有实际需求的,欢迎讨论。
步骤:
1
、在客户端(本例中客户端为通讯机)使用
sendUrgentData
()方法时,请设置一个报
文
中不可能出现的数字,本案例中使用的是
-16
。
2、
在服务端的处理类(即实现
IoHandlerAdapter
的类,为必须类)的
sessionCreated
方法内设置
SO_OOBINLINE
为
true.
代码如下:
@Override
public
void
sessionCreated(IoSession session)
throws
Exception {
IoSessionConfig
cfg = session.getConfig();
if
(cfg
instanceof
SocketSessionConfig) {
((SocketSessionConfig) cfg).setOobInline(
true
);
}
}
3、
在服务端的解码器中将接受到的
-16
的字符全部手动抛弃(注意
IoBuff
三属性的重新设定)。
至此问题解决,但从解决方法来看,这个方法并不具有代表性,当碰到以下情况是并不一定适用:
情况一:
报文的内容本身有可能无所不包,那么
sendUrgentData
设置什么好呢??
情况二:
客户端的程序无法改动时,又该如何应对呢??
当然这个问题的终结解决方案并不在本文的讨论范围之类,这个很明显就是
mina
的一个
BUG
,不知道
2.04
的版本有没有解决这个问题,但从官网所贴的问题列表来看,这个
BUG
应该是依旧存在的,奈何笔者
E
文比较烂,看看资料还可以,要我动手写,并将以上内容用
E
文表达出来,确实是没有那个勇气的,希望能看到这一段的童鞋能代劳一、二,督促官方早日改好这个
BUG
,咱也算是为开源软件尽了一份力不是?
^_^
有的童鞋看到这里可能会说笔者是不是太啰嗦了,几句话可以解决的事情讲这么多,这里我想强调一下的是,本文
的核心内容
主要讲的还是使用心得,
而
不是使用方法,在这里之所以把
解决
过程讲得这么详细,还是希望达成二点目的。
1
、笔者希望通过对过程详细的描述,来提醒大家。做咱们这一行的不可能不遇到问题,但遇到问题首要的是先缩小范围,再确定范围,实际确定不下来的,不妨跟同行讨论一番,如果还确定不下来,咱就暂时放一放,等脑子静下来以后,把思路跳出来,反向追踪,说不定问题的表象并不是问题发生的缘原呢?(这话有点拗口,不做解释。。。。
-_-!!
)在本文中就是一个很明显的例子,明明是调度机表现出来的
CPU
占用过高,但导致这一现象发生的却是在通讯机上了。
2
、再次推荐
JRMC,
这东西真的很好用。独乐乐不如众乐乐~~
什么?你已经知道了?知道了,你怎么不告诉我?你真是坏啊。。。。。。哦
~
漏说了一句
,
这个工具是
Oracle JRockit JDK
自带的,据说这个
JDK
的效率能比普通
JDK
的效率高上
2%-10%
非常适合在生产环境下使用。
什么??你还是知道了??
你,你,你。。。。。。(吐血
ing....
)
当然了,群众的力量是无穷的,大家嫌我太罗嗦的话,下面的内容我就简单一点吧。
注三:
所谓的
native
类型的方法,是
JAVA
中的一种特殊方法,凡是标注这个关键字的方法,其本身并没有任何实现代码,最终的运行都是通过虚拟机调用
OS
的底层的方法来运行的。
这里主要推荐二个集合类,分别是
ConcurrentLinkedQueue
,
ConcurrentHashMap
这二个类的使用基本上不需要你考虑是不是多线程的编程,也不需要用锁,可以大幅提高并发量过大时的对像存取,至于实现机制劳驾大家自己去
GOOGLE
一把吧。
文章到这里基本上算是结束了,而项目最终的并发量从
2680
提升至
3.5W,
客户要求的是
2W
的并发量,所以后面更高的并发没有继续再测,至本文截稿为止,最新的消息是项目的一期工作已经顺利通过了国家级机构的评测。但实质上本文关于
MINA
框架还有很多东西没有涉及到,比如说与
Spring
的结合,对
Jmx
的支持,自定义协议详细举例等等,但我想这点小困难应该不会妨碍大家对
mina
的学习热情吧!感兴趣的童鞋不妨把它当成一个课后作业来做做吧
!!
^_^
分享到:
相关推荐
mina的使用初步入门mina的使用初步入门mina的使用初步入门
一个Apache MINA使用案例源代码ApacheMina
我自己写的使用mina框架实现cmpp2.0服务端,经过一段使用解决了几个bug现在比较稳定。
Mina使用详细教程,这里有详细步骤,和netty是一个母亲
mina的高级使用,mina文件图片传送,
mina-core-2.0及其他相关jar,mina-core-2.0及其他相关jarmina-core-2.0及其他相关jarmina-core-2.0及其他相关jarmina-core-2.0及其他相关jar
工作中的一个小项目,分享给大家参考,望大家不吝批评指教,本人常年从事JAVA软件开发,有丰富的MINA通信软件开发经验,现在已经有成熟的底层框架(结合了反射、DynaBean、Spring等多种技术),可以实现程序自动对...
这是个使用mina的例子,需要的可以下来看看
mina客户端,服务器端的demo
mina socket 使用详解,这个文档简单易懂,是初学者的大大福音。
mina简单事例 博文链接:https://shoushounihao.iteye.com/blog/2008773
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-...
使用MINA实现长连接
服务器框架MINA使用经验总结 socket协议通信框架
2.mina若有空闲连接则使用已有连接,若无则新建mina连接; 3.mina空闲连接超过保活时间25分钟后,自动删除; 4.mina发送指令后,接收指定时长内收到的消息; <groupId>org.apache.mina <artifactId>mina-core ...
Android端集成Mina框架实现长连接,完美解决断线重连问题,修复断线重连打开多端口问题。
一个简单的mina运行DEMO,可以帮助你更好的使用Mina以及了解Mina
里面包含mina2.0的api(英文)和mina自学手册,还有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....
apache-mina-2.0.4 mina框架的源码及jar包