设为首页 收藏本站
查看: 644|回复: 0

[经验分享] apache mina 学习(十三)-----状态机和IoHander配合使用

[复制链接]

尚未签到

发表于 2017-1-11 09:59:10 | 显示全部楼层 |阅读模式
  现在我们把上一张的收录机的例子改造为一个tcp服务器,用文本的传输,效果如下;
telnet localhost 12345S: + Greetings from your tape deck!C: listS: + (1: "The Knife - Silent Shout", 2: "Kings of convenience - Riot on an empty street")C: load 1S: + "The Knife - Silent Shout" loadedC: playS: + Playing "The Knife - Silent Shout"C: pauseS: + "The Knife - Silent Shout" pausedC: playS: + Playing "The Knife - Silent Shout"C: infoS: + Tape deck is playing. Current tape: "The Knife - Silent Shout"C: ejectS: - Cannot eject while playingC: stopS: + "The Knife - Silent Shout" stoppedC: ejectS: + "The Knife - Silent Shout" ejectedC: quitS: + Bye! Please come back!完整的代码在org.apache.mina.example.tapedeck 包中
状态如下:@State public static final String ROOT = "Root";@State(ROOT) public static final String EMPTY = "Empty";@State(ROOT) public static final String LOADED = "Loaded";@State(ROOT) public static final String PLAYING = "Playing";@State(ROOT) public static final String PAUSED = "Paused";事件方法有些变化:@IoHandlerTransitions({@IoHandlerTransition(on = MESSAGE_RECEIVED, in = LOADED, next = PLAYING),@IoHandlerTransition(on = MESSAGE_RECEIVED, in = PAUSED, next = PLAYING)})public void playTape(TapeDeckContext context, IoSession session, PlayCommand cmd) {session.write("+ Playing \"" + context.tapeName + "\"");}我们没有使用上个例子中的Transaction注解,而是用了IoHandlerTransaction注解,当为Mina的IoHandler创建一个状态机时,它会选择让你使用Java enum (枚举)类型来替代我们上面使用的字符串类型。这个在Mina的IoFilter中也是一样的。我们现在使用MESSAGE_RECEIVED来替代"play"来作为事件的名字(on是@IoHandlerTransition的一个属性)。这个常量是在org.apache.mina.statemachine.event.IoHandlerEvents中定义的,它的值是"messageReceived",这个和Mina的IoHandler中的messageReceived()方法是一致的。同时我们自定义了一个StateContext状态上下文的实现TapeDeckContext,主要作用就是用于返回当前收录机的名字。static class TapeDeckContext extends AbstractStateContext {public String tapeName;}playTape()方法使用了PlayCommand命令来作为它的最后的一个参数意味着只有在客户端发送的信息被编码成layCommand命令时,该方法才会被调用
@IoHandlerTransition(on = MESSAGE_RECEIVED, in = EMPTY, next = LOADED)public void loadTape(TapeDeckContext context, IoSession session, LoadCommand cmd) {if (cmd.getTapeNumber() < 1 || cmd.getTapeNumber() > tapes.length) {session.write("- Unknown tape number: " + cmd.getTapeNumber());StateControl.breakAndGotoNext(EMPTY);//如果用户传递了非法的状态,则用empty代替} else {context.tapeName = tapes[cmd.getTapeNumber() - 1];session.write("+ \"" + context.tapeName + "\" loaded");}}connect()方法将会在Mina开启一个会话并调用sessionOpened()方法时触发
@IoHandlerTransition(on = SESSION_OPENED, in = EMPTY)public void connect(IoSession session) {session.write("+ Greetings from your tape deck!");}它所做的工作就是向客户端发送欢迎的信息。状态机将会保持空的状态。pauseTape(), stopTape() 和 ejectTape() 方法和 playTape()很相似  错误处理如下:
@IoHandlerTransition(on = MESSAGE_RECEIVED, in = ROOT, weight = 10)public void error(Event event, StateContext context, IoSession session, Command cmd) {session.write("- Cannot " + cmd.getName() + " while " + context.getCurrentState().getId().toLowerCase());}主方法:private static IoHandler createIoHandler() {StateMachine sm = StateMachineFactory.getInstance(IoHandlerTransition.class).create(EMPTY, new TapeDeckServer());return new StateMachineProxyBuilder().setStateContextLookup(new IoSessionStateContextLookup(new StateContextFactory() {public StateContext create() {return new TapeDeckContext();}})).create(IoHandler.class, sm);}// This code will work with MINA 1.0/1.1:public static void main(String[] args) throws Exception {SocketAcceptor acceptor = new SocketAcceptor();SocketAcceptorConfig config = new SocketAcceptorConfig();config.setReuseAddress(true);ProtocolCodecFilter pcf = new ProtocolCodecFilter(new TextLineEncoder(), new CommandDecoder());config.getFilterChain().addLast("codec", pcf);acceptor.bind(new InetSocketAddress(12345), createIoHandler(), config);}// This code will work with MINA trunk:public static void main(String[] args) throws Exception {SocketAcceptor acceptor = new NioSocketAcceptor();acceptor.setReuseAddress(true);ProtocolCodecFilter pcf = new ProtocolCodecFilter(new TextLineEncoder(), new CommandDecoder());acceptor.getFilterChain().addLast("codec", pcf);acceptor.setHandler(createIoHandler());acceptor.setLocalAddress(new InetSocketAddress(PORT));acceptor.bind();}
  reateIoHandler() 方法创建了一个状态机,这个和我们之前所做的相似。除了我们一个IoHandlerTransition.class类来代替Transition.class 在StateMachineFactory.getInstance(...)方法中。这是我们在使用 @IoHandlerTransition 声明的时候必须要做的。当然这时我们使用了一个IoSessionStateContextLookup和一个自定义的StateContextFactory类,这个在我们创建一个IoHandler代理时被使用到了。如果我们没有使用IoSessionStateContextLookup ,那么所有的客户端将会使用同一个状态机,这是我们不希望看到的。
  main()方法创建了SocketAcceptor实例,并且绑定了一个ProtocolCodecFilter ,它用于编解码命令对象。最后它绑定了12345端口和IoHandler的实例。这个oHandler实例是由createIoHandler()方法创建的。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-326870-1-1.html 上篇帖子: Apache james mailserver + Claros inTouch webmail搭建邮箱应用 下篇帖子: org.apache.commons.lang 常用方法介绍 及 ToStringBuilder学习
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表