梦幻之旅
DEBUG - 天道酬勤
::
首页
::
新随笔
::
联系
::
聚合
::
管理
::
671 随笔 :: 6 文章 :: 256 评论 :: 0 Trackbacks
<
2011年9月
>
日
一
二
三
四
五
六
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
公告
本博客中未注原创的文章均为转载,对转载内容可能做了些修改和增加图片注释,如果侵犯了您的版权,或没有注明原作者,请谅解
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(21)
给我留言
查看公开留言
查看私人留言
随笔分类
(644)
Android(10)
(rss)
ANT(4)
(rss)
C#(10)
(rss)
C/C++(16)
(rss)
CSS(3)
(rss)
DataBase(119)
(rss)
DB-DailyMmaintenance(16)
(rss)
Design Patterns(27)
(rss)
english
(rss)
Exceptions(7)
(rss)
EXT(39)
(rss)
FLASH(9)
(rss)
Hardware(20)
(rss)
Hibernate(13)
(rss)
Html(23)
(rss)
Java(143)
(rss)
java Net(10)
(rss)
JavaScript(39)
(rss)
Linux(26)
(rss)
php(5)
(rss)
Regular Exp(3)
(rss)
Spring(17)
(rss)
Struts(12)
(rss)
TOOL(43)
(rss)
VB/VBA/VBS(5)
(rss)
webservice(9)
(rss)
XML(2)
(rss)
我的梦幻旅途(14)
(rss)
随笔档案
(669)
2017年9月 (4)
2016年10月 (1)
2015年6月 (1)
2015年4月 (2)
2015年1月 (1)
2014年8月 (2)
2014年7月 (9)
2014年6月 (1)
2014年5月 (2)
2014年4月 (3)
2014年3月 (3)
2013年10月 (4)
2013年9月 (8)
2013年8月 (4)
2013年6月 (3)
2013年5月 (4)
2013年4月 (7)
2013年3月 (1)
2013年1月 (3)
2012年12月 (4)
2012年11月 (1)
2012年10月 (1)
2012年9月 (4)
2012年8月 (1)
2012年7月 (2)
2012年6月 (1)
2012年5月 (4)
2012年4月 (2)
2012年3月 (1)
2012年2月 (4)
2012年1月 (6)
2011年12月 (10)
2011年11月 (7)
2011年10月 (6)
2011年9月 (37)
2011年8月 (34)
2011年7月 (44)
2011年6月 (10)
2011年5月 (5)
2011年4月 (3)
2011年3月 (1)
2011年2月 (1)
2011年1月 (18)
2010年12月 (9)
2010年11月 (13)
2010年10月 (17)
2010年9月 (2)
2010年8月 (10)
2010年7月 (10)
2010年6月 (5)
2010年5月 (8)
2010年4月 (9)
2010年3月 (11)
2010年2月 (3)
2010年1月 (8)
2009年12月 (6)
2009年11月 (10)
2009年10月 (5)
2009年9月 (1)
2009年8月 (18)
2009年7月 (6)
2009年6月 (2)
2009年5月 (1)
2009年4月 (4)
2009年3月 (6)
2009年2月 (5)
2009年1月 (3)
2008年12月 (13)
2008年11月 (13)
2008年10月 (30)
2008年9月 (9)
2008年8月 (24)
2008年7月 (17)
2008年6月 (15)
2008年5月 (16)
2008年4月 (15)
2008年3月 (19)
2008年2月 (3)
2008年1月 (20)
2007年12月 (24)
2007年11月 (9)
文章档案
(6)
2008年4月 (1)
2008年3月 (1)
2008年1月 (2)
2007年11月 (2)
最新随笔
1. PP代码生成器(四) 使用解决方案生成代码
2. PP代码生成器(三) 设计freemarker模板, 创建解决方案
3. PP代码生成器(二) 解决方案, 生成任务, 辅助设计面板
4. PP代码生成器(一) 简介, 下载, 运行
5. PP持久层代码生成器
6. 比较好的博客
7. 系统集成项目管理工程师
8. 软件公司项目经理岗位职责
9. 联想笔记本 显示屏 键盘失灵 释放静电
10. eclipse maven
积分与排名
积分 - 953998
排名 - 37
最新评论
1. re: Myeclipse 快捷键大全(绝对全)
crl+向右箭头(输入法有问题打不出来)移到下一个参数的位置,然后crl+shift+向右箭头 选中该位置的参数即可
--红领巾
2. re: Log4j基本使用方法
555
--555
3. re: Myeclipse 快捷键大全(绝对全)[未登录]
很不错,谢谢
--银狐
4. re: Flex 表单
是谁这么无聊~呜~~~
--HUIKK
5. re: Spring AfterReturning 异常
具体是什么意思啊
--dingli
阅读排行榜
1. Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream(70015)
2. log4j.properties 使用说明(42070)
3. Myeclipse 快捷键大全(绝对全)(32711)
4. TNSNAMES.ORA 配置(24380)
5. oracle 树状查询(21351)
评论排行榜
1. Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream(53)
2. JMail 异常: java.lang.NoClassDefFoundError: javax/activation/DataSource(21)
3. javax.mail.MessagingException: 530 5.7.0 Must issue a STARTTLS command first(14)
4. java 读取 excel 2003 或 excel 2007(14)
5. java.lang.UnsupportedClassVersionError: Bad version number in .class file(8)
(转)MINA2 之IoBuffer
最近做的一个项目用到了开源的C
/
S应用的服务器框架MINA,当初做的时候资料非常少,只能自己不停的测试,总结出了一些规律经验。
从网上看的资料上看,这个服务器框架还是比较稳定和支持的并发数还是很不错的,不过没有准确的数据,而且我做完的时候也没有拿到真正的实际环境中测试过,用的时候也发现了很多优点和缺点,使用者可以自己去根据自己的使用需求去衡量是否使用该框架。
服务器是商业系统很重要的一部分,主要负责数据采集,文件分发,与端机的通信,和自动作业等任务,服务器大多是24小时运行的,因此服务器的实现必须强壮、稳定、安全,而速度虽然也是很重要,不过最重要的还是前三者。服务器框架MINA就是要为这样的服务器提供了一个网络应用框架,当然这样的服务器框架也可以自己去实现。MINA为我们封装了socket的底层通信实现,提供了日志,线程池等功能,使用起来非常简单、方便。
MINA是一个异步框架,是通过网络事件激发的,它包含两层:IO层和协议层。首先介绍IO层,要说明的是我用的版本是0.
8.2
,可能不同版本会稍有不同。
Client产生一个底层IO事件,比如说连接和发送数据包,IoAcceptor执行所有底层IO,将他们翻译成抽象的IO事件,接着这里可以添加(也可以部添加)一个IoFilters对IO事件进行过滤,并把翻译过的事件或过滤过的事件和关联的IoSession 发送给IoHandler。IoSession是一个有效的网络连接会话,此会话将一直保持连接,除非网络断开或用户主动断开连接(session.close()),用户可以通过IoSession获得有关该会话连接的信息和配置会话的对象和属性;IoHandler是网络事件的监听器,也就是说当有网络事件发生时会通知IoHandler,用户不用去主动接受数据。用户只要实现此接口爱干吗干吗去吧。IoFilter:Io过滤器,对Io事件进行过滤,比如添加日志过滤器和线程池过滤器。
使用说明:
import
java.util.logging.Level;
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.common.IdleStatus;
import
org.apache.mina.common.SessionConfig;
import
org.apache.mina.io.IoHandlerAdapter;
import
org.apache.mina.io.IoSession;
import
org.apache.mina.io.socket.SocketSessionConfig;
import
org.apache.mina.util.SessionLog;
public
class
ServerHandler
extends
IoHandlerAdapter
{
public
ServerHandler()
{
}
public
void
dataRead(IoSession session, ByteBuffer buffer)
throws
Exception
{
//
当有数据读入时此方法被调用,数据封装在ByteBuffer中,可以用以下方法对出buffer的数据,ByteBuffer的数据读出后内存中就没有了。
//
String message = "";
//
byte[] bytes = new byte[rb.remaining()];
//
int j = 0;
//
while (rb.hasRemaining()) {
//
bytes[j++] = rb.get();
//
}
//
message = new String(bytes);
//
接着可以进行逻辑处理
}
public
void
dataWritten(IoSession session, Object mark)
throws
Exception
{
//
当数据被写入通道时此方法被调用,实际就是调用了session.write(IoSession,Object)方法
SessionLog.log(Level.INFO,session,mark.toString());
//
必要时打印所写入的内容,mark的内容就是session.write(session,mark)中的第二个参数
}
public
void
exceptionCaught(IoSession session, Throwable arg1)
throws
Exception
{
//
当出现异常时此方法被调用,从而进行各种异常处理,该方法可以捕捉网络异常(如连接非正常关闭)和所有其他方法产生的异常,这里要注意如果客户端要保持与服务器端的连接时不要在这里马上重新连接不然会抛出CancelKeyException运行期异常直接导致程序死掉(特别是与服务器端有超过两个连接时一定会发生并且此异常无法捕获),建议的方法是启动一个单独的线程来完成与服务器端的重新连接,还有要注意的是如果网络是正常关闭的,比如说是客户端正常关闭连接,而此时服务器端是不愿意关闭的话,这个异常本方法是捕捉不了的,因此只能在session.close()方法中处理这种情况。
session.close();
}
public
void
sessionClosed(IoSession session)
throws
Exception
{
//
当网络连接被关闭是此方法被调用
SessionLog.log(Level.INFO,session,
"
Close a Session
"
);
//
必要时打印出信息
}
public
void
sessionCreated(IoSession session)
throws
Exception
{
//
当网络连接被创建时此方法被调用(这个肯定在sessionOpened(IoSession session)方法之前被调用),这里可以对Socket设置一些网络参数
SessionConfig cfg
=
session.getConfig();
if
(cfg
instanceof
SocketSessionConfig)
{
((SocketSessionConfig) cfg).setSessionReceiveBufferSize(
2048
);
((SocketSessionConfig) cfg).setKeepAlive(
true
);
((SocketSessionConfig) cfg).setSoLinger(
true
,
0
);
((SocketSessionConfig) cfg).setTcpNoDelay(
true
);
((SocketSessionConfig) cfg).setWriteTimeout(
1000
*
5
);
}
}
public
void
sessionIdle(IoSession arg0, IdleStatus arg1)
throws
Exception
{
//
当网络通道空闲时此方法被调用,在这里可以判断是读空闲、写空闲还是两个都空闲,以便做出正确的处理
一半的网络通讯程序都要与服务器端保持长连接,所以这里可以发一下网络测试数据以保持与服务器端的连接
}
public
void
sessionOpened(IoSession session)
throws
Exception
{
//
当网络连接被打开时此方法被调用,这里可以对session设置一些参数或者添加一些IoFilter的实现,也可以对客户端做一些认证之类的工作
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,
60
);
}
}
//
启动监听连接的服务器
import
org.apache.mina.common.
*
;
import
org.apache.mina.io.
*
;
import
org.apache.mina.io.filter.
*
;
import
org.apache.mina.registry.
*
;
public
class
Server
{
/** */
/**
Choose your favorite port number.
*/
private
static
final
int
PORT
=
8080
;
public
static
void
main( String[] args )
throws
Exception
{
ServiceRegistry registry
=
new
SimpleServiceRegistry();
//
可以添加各种过滤器,比如线程池过滤器,增加一个线程池处理来自不同的连接
IoAcceptor ioAcceptor
=
registry.getIoAcceptor();
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
ioAcceptor.getFilterChain().addLast(
"
IoThreadPool
"
,
ioThreadPoolFilter);
//
Bind
Service service
=
new
Service(
"
serviceName
"
,
TransportType.SOCKET, PORT );
registry.bind( service,
new
ServerHandler() );
System.out.println(
"
Listening on port
"
+
PORT );
}
}
//
如果是连接服务器的可以如下启动连接请求
import
org.apache.mina.io.filter.IoThreadPoolFilter;
import
org.apache.mina.io.socket.SocketConnector;
import
java.net.InetSocketAddress;
public
class
Client
{
public
static
void
main( String[] args )
throws
Exception
{
private
static
final
int
CONNECT_TIMEOUT
=
3
;
//
设置超时连接时间
//
可以添加各种过滤器,比如线程池过滤器,增加一个线程池处理来自不同的连接
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
SocketConnector connector
=
new
SocketConnector();
connector.getFilterChain().addFirst(
"
threadPool
"
,
ioThreadPoolFilter);
//
初始化客户端的监听处理器
ClientHandler clientHandler
=
new
ClientHandler();
InetSocketAddress address
=
new
InetSocketAddress(
"
serverIp
"
,serverPort);
try
{
connector.connect(address, CONNECT_TIMEOUT,
clientHandler);
System.out.println(
"
connect sucessfully!
"
);
}
catch
(Exception e)
{
System.err.println(
"
Failed to connect.
"
);
}
}
如果一个协议非常复杂,如果只用一个Io层是非常复杂的,因为IO层没有帮助你分离‘message解析’和‘实际的业务逻辑,MINA提供了一个协议层来解决这个问题。
使用协议层必须实现5个接口:ProtocolHandler, ProtocolProvider, ProtocolCodecFactory, ProtocolEncoder, 和 ProtocolDecoder:
第一步:实现ProtocolDecoder和ProtocolEncoder,当有IO事件时便先调用这两个类的方法
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.protocol.ProtocolDecoderOutput;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.protocol.ProtocolViolationException;
import
org.apache.mina.protocol.codec.MessageDecoder;
import
org.apache.mina.protocol.codec.MessageDecoderResult;
import
java.util.
*
;
public
class
ServerDecoder
implements
MessageDecoder
{
public
ServerTranInfoDecoder()
{
}
public
MessageDecoderResult decodable(ProtocolSession session, ByteBuffer in)
{
//
对接受的数据判断是否与协议相同,如果相同返回MessageDecoderResult.OK,否则返回MessageDecoderResult.NOT_OK,这里如果要从ByteBuffer读出数据,需要重新用ByteBuffer.put(ByteBuffer)放回内存中,以便decode方法使用;
return
MessageDecoderResult.OK;
return
MessageDecoderResult.NOT_OK;
}
public
MessageDecoderResult decode(ProtocolSession session, ByteBuffer in,
ProtocolDecoderOutput out)
throws
ProtocolViolationException
{
//
根据协议将介绍到的数据(放在ByteBuffer中)组装成相对应的实体,调用out.write(Object)方法发送给协议层进行业务逻辑的处理,如果成功返回MessageDecoderResult.OK,否则返回MessageDecoderResult.NOT_OK;
out.write(object);
}
import
org.apache.mina.common.ByteBuffer;
import
org.apache.mina.protocol.ProtocolEncoderOutput;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.protocol.ProtocolViolationException;
import
org.apache.mina.protocol.codec.MessageEncoder;
import
java.util.
*
;
public
class
ServerEncoder
implements
MessageEncoder
{
public
static
Set TYPES;
public
ServerEncoder()
{
}
public
Set getMessageTypes()
{
HashSet set
=
new
HashSet();
set.add(Send.
class
);
//
增加要进行编码的实体类
TYPES
=
Collections.unmodifiableSet( set );
return
TYPES;
}
public
void
encode( ProtocolSession session, Object message, ProtocolEncoderOutput out )
throws
ProtocolViolationException
{
//
将回应报文实体message编码层returnStr后发送到客户端
byte
[] bytes
=
returnStr.getBytes();
ByteBuffer rb
=
ByteBuffer.allocate(bytes.length);
rb.put(bytes);
rb.flip();
out.write(rb);
}
}
第二步:实现ProtocolCodecFactory
import
org.apache.mina.protocol.codec.DemuxingProtocolCodecFactory;
public
class
ServerProtocolCodecFactory
extends
DemuxingProtocolCodecFactory
{
public
ServerProtocolCodecFactory(
boolean
server)
{
if
(server)
{
super
.register(ServerDecoder.
class
);
super
.register(ServerEncoder.
class
);
}
}
}
第三步:实现ProtocolHandler,在有IO事件发生后,经过decode和encode的处理后就把协议实体交个这个处理器进行业务逻辑的处理,因此实现了协议解释和业务逻辑的分离,它与IoHandler非常相似,不过这里处理的是经过编码与解码后的对象实体。
import
org.apache.mina.common.IdleStatus;
import
org.apache.mina.protocol.ProtocolSession;
import
org.apache.mina.util.SessionLog;
import
org.apache.mina.protocol.handler.DemuxingProtocolHandler;
public
class
ServerSessionHandler
extends
DemuxingProtocolHandler
{
public
ServerSessionHandler()
{
}
public
void
sessionCreated(ProtocolSession session)
throws
Exception
{
}
public
void
sessionOpened(ProtocolSession session)
throws
Exception
{
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE,
60
);
}
public
void
sessionClosed(ProtocolSession session)
{
}
public
void
messageReceived(ProtocolSession session, Object message)
throws
Exception
{
//
根据解码后的message,进行业务逻辑的处理
session.close();
}
public
void
messageSent(ProtocolSession session, Object message)
{
}
public
void
sessionIdle(ProtocolSession session, IdleStatus status)
throws
Exception
{
//
网络出现空闲时进行处理,并关掉连接
session.close();
}
public
void
exceptionCaught(ProtocolSession session, Throwable cause)
{
cause.printStackTrace();
//
处理所有Handler方法抛出的异常,和Mina架构抛出的异常,并关掉连接
session.close();
}
}
第四步:实现ProtocolProvider
import
org.apache.mina.protocol.
*
;
public
class
ServerProtocolProvider
implements
ProtocolProvider
{
private
static
final
ProtocolCodecFactory CODEC_FACTORY
=
new
SemsProtocolCodecFactory(
true
);
private
static
final
ProtocolHandler HANDLER
=
new
ServerSessionHandler();
public
ServerProtocolProvider()
{
}
public
ProtocolCodecFactory getCodecFactory()
{
return
CODEC_FACTORY;
}
public
ProtocolHandler getHandler()
{
return
HANDLER;
}
}
这样协议层便完成了,启动时跟IO层的差不多,不过我们还可以在IO层和协议层用两个线程池,如下:
public
class
Server
{
//
服务器的监听端口号
public
static
final
int
SERVER_PORT
=
8000
;
public
static
void
main(String[] args)
{
//
进行服务器的相关配置
ServiceRegistry registry
=
new
SimpleServiceRegistry();
IoProtocolAcceptor protocolAcceptor
=
(IoProtocolAcceptor) registry
.getProtocolAcceptor(TransportType.SOCKET);
ProtocolThreadPoolFilter protocolThreadPoolFilter
=
new
ProtocolThreadPoolFilter();
protocolThreadPoolFilter.setMaximumPoolSize(
10
);
protocolThreadPoolFilter.start();
protocolAcceptor.getFilterChain().addLast(
"
IoProtocolThreadPool
"
,
protocolThreadPoolFilter);
IoAcceptor ioAcceptor
=
protocolAcceptor.getIoAcceptor();
IoThreadPoolFilter ioThreadPoolFilter
=
new
IoThreadPoolFilter();
ioThreadPoolFilter.setMaximumPoolSize(
10
);
ioThreadPoolFilter.start();
ioAcceptor.getFilterChain().addLast(
"
IoThreadPool
"
,
ioThreadPoolFilter);
Service service
=
new
Service(
"
TranServer
"
, TransportType.SOCKET,
SERVER_PORT);
//
绑定了刚刚实现的ServerProtocolProvider
registry.bind(service,
new
ServerProtocolProvider());
}
整个MINA框架经常用到的就是这些了,这样的事件触发框架和两层框架使用起来非常方便,不过这种异步框架还是有些非常明显的缺陷:
第一,MINA只会为每个Session分配一个线程,也就是只能一个一个事件按顺序执行,就算你在某个方法执行时产生了新的事件,比如收到新的数据,MINA也会先将该事件缓冲起来,所以你在执行某个方法时是不可能执行dataRead方法的,所以MINA框架是不会阻塞的,要想在一个逻辑方法中实现交互是实现不了的,因此要想出另外的实现方法。
第二,如果客户端发完一个数据给服务器就想马上得到回复,而不等整个业务逻辑执行完,也是实现不到的,因为MINA框架要将整个接收事件处理完了,再把回复信息发给客户端。
第三,如果MINA是作为服务器端等待连接的,当客户端正常关闭后业务逻辑也可继续正常执行,但是如果MINA是连接服务器的客户端,则当服务器关闭后,MINA的session也会关闭。
最后要说明的是MINA使用的线程池是用Leader
/
Followers Tread Pool实现的,默认最大支持2G的线程。当然MINA框架是开源的,用户可以根据自己的需要改写代码,而其MINA的功能也是不断可以扩展的。
以上是我使用MINA的经验总结,其实MINA的相关文档和例子也介绍了很多了,我这里算是一个总结吧,不过有很多地方只是我的个人见解,不一定正确,如果有不对的,希望高手可以提出。
http://riddickbryant.iteye.com/blog/564415
posted on 2011-09-05 00:40
HUIKK
阅读(4607)
评论(0)
编辑
收藏
所属分类:
java Net
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
知识库
C++博客
博问
管理
相关文章:
TCP一点东东
(转)MINA2 之IoBuffer
(转)Mina 框架总结
socketPool
apache mina框架小试
jboss netty 框架小试
java 简单socket 通信
[转]JAVA-用HttpClient来模拟浏览器GET,POST
UDP
java 得到本机所有ip
Powered by:
BlogJava
Copyright © HUIKK