代码改变世界

Apache Mina实战

2013-09-18 11:07  飘扬的红领巾  阅读(1224)  评论(0编辑  收藏  举报

Mina介绍

Mina可以用于快速的开发基于网络通信的应用,特别是在开发手机端的游戏应用时,使用的较为普遍。本文简单介绍了一个用Mina搭建的一个简易讨论组,通过该应用可以对Mina的基本用法用途有个大致的了解。

界面效果

界面元素不多,使用了两个AWT组件。

客户端1:

image

客户端2:

image

服务端日志:

image

核心代码

服务端Handler

   1: /**
   2:  * <服务端消息Handler>
   3:  * 
   4:  * @author liping.action@gmail.com
   5:  * @version V1.0
   6:  */
   7: public class ServerMessageHandler extends IoHandlerAdapter {
   8:     private MsgQueue msgQueueReceived;
   9:     private MsgQueue msgQueueSent;
  10:     
  11:     public MsgQueue getMsgQueueReceived() {
  12:         return msgQueueReceived;
  13:     }
  14:  
  15:     public void setMsgQueueReceived(MsgQueue msgQueueReceived) {
  16:         this.msgQueueReceived = msgQueueReceived;
  17:     }
  18:  
  19:     public MsgQueue getMsgQueueSent() {
  20:         return msgQueueSent;
  21:     }
  22:  
  23:     public void setMsgQueueSent(MsgQueue msgQueueSent) {
  24:         this.msgQueueSent = msgQueueSent;
  25:     }
  26:  
  27:     static {
  28:         PropertyConfigurator.configure(ClassLoader
  29:                 .getSystemResource("log4j.properties"));
  30:     }
  31:     private static Logger logger = Logger.getLogger(ServerMessageHandler.class);
  32:  
  33:     @Override
  34:     public void exceptionCaught(IoSession session, Throwable cause)
  35:             throws Exception {
  36:         logger.error(cause.toString());
  37:     }
  38:  
  39:     @Override
  40:     public void messageReceived(IoSession session, Object message)
  41:             throws Exception {
  42:         Msg msg = (Msg) message;
  43:         logger.info("MSG:from=" + session.getRemoteAddress() + ",id="
  44:                 + msg.getId() + ",content=" + msg.getContent());
  45:         Collection<IoSession> sessions = session.getService()
  46:                 .getManagedSessions().values();
  47:         msg.setId(session.getRemoteAddress().toString());
  48:         for (IoSession ioSession : sessions) {
  49:             ioSession.write(msg);
  50:         }
  51:     }
  52:  
  53:     @Override
  54:     public void messageSent(IoSession session, Object message) throws Exception {
  55:         logger.info(Constant.MESSAGE_SENT);
  56:     }
  57:  
  58:     @Override
  59:     public void sessionClosed(IoSession session) throws Exception {
  60:         logger.info(Constant.SESSION_CLOSED);
  61:     }
  62:  
  63:     @Override
  64:     public void sessionCreated(IoSession session) throws Exception {
  65:         logger.info(Constant.SESSION_CREATED);
  66:     }
  67:  
  68:     @Override
  69:     public void sessionIdle(IoSession session, IdleStatus status)
  70:             throws Exception {
  71:         logger.info(Constant.SESSION_IDLE);
  72:     }
  73:  
  74:     @Override
  75:     public void sessionOpened(IoSession session) throws Exception {
  76:         logger.info(Constant.SESSION_OPENED);
  77:         logger.info("address : "
  78:                 + session.getRemoteAddress());
  79:     }
  80:  
  81: }

客户端handler

   1: /**
   2:  * <客户端handler>
   3:  * 
   4:  * @author liping.action@gmail.com
   5:  * @version V1.0
   6:  */
   7: public class ClientMessageHanlder extends IoHandlerAdapter {
   8:     private static Logger logger = Logger.getLogger(ClientMessageHanlder.class);
   9:     private MsgModel msgModel;
  10:     
  11:     public MsgModel getMsgModel() {
  12:         return msgModel;
  13:     }
  14:  
  15:     public void setMsgModel(MsgModel msgModel) {
  16:         this.msgModel = msgModel;
  17:     }
  18:  
  19:     @Override
  20:     public void exceptionCaught(IoSession session, Throwable cause)
  21:             throws Exception {
  22:         super.exceptionCaught(session, cause);
  23:     }
  24:  
  25:     @Override
  26:     public void messageReceived(IoSession session, Object message)
  27:             throws Exception {
  28:         Msg msg = (Msg) message;
  29:         logger.info("msg:id=" + msg.getId() + ",content=" + msg.getContent());
  30:         msgModel.setMsg(msg);
  31:         msgModel.fireModelChange();//触发模型变更,通知观察者
  32:     }
  33:  
  34:     @Override
  35:     public void messageSent(IoSession session, Object message) throws Exception {
  36:         super.messageSent(session, message);
  37:     }
  38:  
  39:     @Override
  40:     public void sessionClosed(IoSession session) throws Exception {
  41:         super.sessionClosed(session);
  42:     }
  43:  
  44:     @Override
  45:     public void sessionCreated(IoSession session) throws Exception {
  46:         super.sessionCreated(session);
  47:     }
  48:  
  49:     @Override
  50:     public void sessionIdle(IoSession session, IdleStatus status)
  51:             throws Exception {
  52:         super.sessionIdle(session, status);
  53:     }
  54:  
  55:     @Override
  56:     public void sessionOpened(IoSession session) throws Exception {
  57:         Msg msg = new Msg(session.getRemoteAddress().toString(),
  58:                 session.getLocalAddress() + " " + DateUtil.getCurrentData() + " 进入了讨论组!");
  59:         session.write(msg);
  60:     }
  61: }

服务端启动器:

   1: /**
   2:  * 服务端启动器
   3:  * 
   4:  */
   5: public class ServerLauncher {
   6:     static {
   7:         PropertyConfigurator.configure(ClassLoader
   8:                 .getSystemResource("log4j.properties"));
   9:     }
  10:     private static Logger logger = Logger.getLogger(ServerMessageHandler.class);
  11:  
  12:     public static void main(String[] args) {
  13:         // 创建一个非阻塞的server端Socket ,用NIO
  14:         SocketAcceptor acceptor = new NioSocketAcceptor();
  15:         // 创建接收数据的过滤器
  16:         DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
  17:         // 设定这个过滤器将以对象为单位读取数据
  18:         ProtocolCodecFilter filter = new ProtocolCodecFilter(
  19:                 new ObjectSerializationCodecFactory());
  20:         chain.addLast("objectFilter", filter);
  21:         // 设定服务器消息处理器
  22:         acceptor.setHandler(new ServerMessageHandler());
  23:         // 服务器绑定的端口
  24:         int bindPort = 9988;
  25:         // 绑定端口,启动服务器
  26:         try {
  27:             acceptor.bind(new InetSocketAddress(bindPort));
  28:         } catch (IOException e) {
  29:             logger.error(e.toString());
  30:         }
  31:         logger.info("Mina Server run done! on port:" + bindPort);
  32:     }
  33: }

客户端启动器:

   1: /**
   2:  * 客户端启动器
   3:  * 
   4:  */
   5: public class ClientLauncher {
   6:     static {
   7:         PropertyConfigurator.configure(ClassLoader
   8:                 .getSystemResource("log4j.properties"));
   9:     }
  10:  
  11:     public static void main(String[] args) {
  12:         // 创建消息模型(被观察者)
  13:         MsgModel model = new MsgModel();
  14:         // 创建一个tcp/ip 连接
  15:         NioSocketConnector connector = new NioSocketConnector();
  16:         /*---------接收对象---------*/
  17:         // 创建接收数据的过滤器
  18:         DefaultIoFilterChainBuilder chain = connector.getFilterChain();
  19:         // 设定这个过滤器将以对象为单位读取数据
  20:         ProtocolCodecFilter filter = new ProtocolCodecFilter(
  21:                 new ObjectSerializationCodecFactory());
  22:         chain.addLast("objectFilter", filter);
  23:         ClientMessageHanlder hanlder = new ClientMessageHanlder();
  24:         hanlder.setMsgModel(model);
  25:         // 设定客户端端的消息处理器
  26:         connector.setHandler(hanlder);
  27:         // Set connect timeout.
  28:         connector.setConnectTimeoutCheckInterval(30);
  29:         // 连结到服务器:
  30:         final ConnectFuture cf = connector.connect(new InetSocketAddress(
  31:                 "127.0.0.1", 9988));
  32:         createComponent(model, cf);
  33:         cf.awaitUninterruptibly();
  34:         cf.getSession().getCloseFuture().awaitUninterruptibly();
  35:         connector.dispose();
  36:     }
  37:  
  38:     private static void createComponent(MsgModel model, final ConnectFuture cf) {
  39:         JFrame frame = new JFrame("Client");
  40:         frame.setLocation(450, 300);
  41:         final TextField textField = new TextField();
  42:  
  43:         textField.addKeyListener(new KeyListener() {
  44:             public void keyTyped(KeyEvent arg0) {
  45:             }
  46:  
  47:             public void keyReleased(KeyEvent arg0) {
  48:             }
  49:  
  50:             public void keyPressed(KeyEvent arg0) {
  51:                 if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
  52:                     String value = textField.getText();
  53:                     if (!value.equals("")) {
  54:                         Msg msg = new Msg("0002", value);
  55:                         cf.getSession().write(msg);
  56:                         textField.setText("");
  57:                     }
  58:                 }
  59:             }
  60:         });
  61:         // 自定义TextArea
  62:         CusTextArea textArea = new CusTextArea();
  63:         model.addObserver(textArea);
  64:         frame.setSize(300, 450);
  65:         frame.setResizable(false);
  66:         frame.setBackground(Color.white);
  67:         frame.add(textField, BorderLayout.SOUTH);
  68:         frame.add(textArea, BorderLayout.NORTH);
  69:         frame.pack();
  70:         frame.setVisible(true);
  71:         frame.addWindowListener(new CloseHandler(cf.getSession()));
  72:         textField.requestFocus();
  73:     }
  74: }

结语

该应用为一个简单的讨论组程序,可实现多人讨论,说白了是重复造轮子,但通过此应用可以对mima的用法及原理进行简单了解。程序还有其他代码没有贴上来,全部由三部分组成,服务端、客户端、公共组件。公共组件提供服务端、客户端公共使用的部分,如消息,消息队列,消息模型等。如需要程序源码,联系我的邮件获取。

下载地址