Apache Mina實戰

飄揚的紅領巾發表於2013-09-18

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的用法及原理進行簡單瞭解。程式還有其他程式碼沒有貼上來,全部由三部分組成,服務端、客戶端、公共元件。公共元件提供服務端、客戶端公共使用的部分,如訊息,訊息佇列,訊息模型等。如需要程式原始碼,聯絡我的郵件獲取。

下載地址

相關文章