apache mina 学习(十三)-----状态机和IoHander配合使用

现在我们把上一张的收录机的例子改造为一个tcp服务器,用文本的传输,效果如下;

telnet localhost 12345 S: + Greetings from your tape deck! C: list S: + (1: "The Knife - Silent Shout", 2: "Kings of convenience - Riot on an empty street") C: load 1 S: + "The Knife - Silent Shout" loaded C: play S: + Playing "The Knife - Silent Shout" C: pause S: + "The Knife - Silent Shout" paused C: play S: + Playing "The Knife - Silent Shout" C: info S: + Tape deck is playing. Current tape: "The Knife - Silent Shout" C: eject S: - Cannot eject while playing C: stop S: + "The Knife - Silent Shout" stopped C: eject S: + "The Knife - Silent Shout" ejected C: quit S: + 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()方法创建的。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要生成一个hostkeyfile给Apache Mina-sshd使用,可以使用Java中的KeyPairGenerator类来生成一个公钥和私钥对。以下是一个示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.util.Base64; public class SSHKeyGenerator { public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException { // Generate a key pair KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // Print the private key byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); String privateKey = Base64.getEncoder().encodeToString(privateKeyBytes); System.out.println("Private key:"); System.out.println(privateKey); // Print the public key byte[] publicKeyBytes = keyPair.getPublic().getEncoded(); String publicKey = Base64.getEncoder().encodeToString(publicKeyBytes); System.out.println("Public key:"); System.out.println(publicKey); } } ``` 该程序将生成一个2048位的RSA密钥对,并打印出私钥和公钥的Base64编码。你可以将私钥保存到文件中并将其用作hostkeyfile。要保存私钥,可以使用以下代码: ```java import java.io.FileOutputStream; import java.io.IOException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.util.Base64; public class SSHKeyGenerator { public static void main(String[] args) throws NoSuchAlgorithmException, IOException { // Generate a key pair KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // Save the private key to a file byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); String privateKey = Base64.getEncoder().encodeToString(privateKeyBytes); FileOutputStream outputStream = new FileOutputStream("hostkeyfile"); outputStream.write(privateKey.getBytes()); outputStream.close(); } } ``` 该程序将生成一个2048位的RSA密钥对,并将私钥保存到名为hostkeyfile的文件中。该文件可以通过Apache Mina-sshd的配置文件进行引用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值