底層架構-遠程通訊-Mina

          一:Mina概要
              Apache Mina是一個能夠幫助用戶開發高性能和高伸縮性網絡應用程序的框架。它通過Java nio技術基于TCP/IP和UDP/IP協議提供了抽象的、事件驅動的、異步的API。
          如下的特性:
          1、  基于Java nio的TCP/IP和UDP/IP實現
          基于RXTX的串口通信(RS232)
          VM 通道通信
          2、通過filter接口實現擴展,類似于Servlet filters
          3、low-level(底層)和high-level(高級封裝)的api:
                 low-level:使用ByteBuffers
                 High-level:使用自定義的消息對象和解碼器
          4、Highly customizable(易用的)線程模式(MINA2.0 已經禁用線程模型了):
                 單線程
                 線程池
                 多個線程池
          5、基于java5 SSLEngine的SSL、TLS、StartTLS支持
          6、負載平衡
          7、使用mock進行單元測試
          8、jmx整合
          9、基于StreamIoHandler的流式I/O支持
          10、IOC容器的整合:Spring、PicoContainer
          11、平滑遷移到Netty平臺

          二:實踐
              首先講一下客戶端的通信過程:
          1.通過SocketConnector同服務器端建立連接 
          2.鏈接建立之后I/O的讀寫交給了I/O Processor線程,I/O Processor是多線程的 
          3.通過I/O Processor讀取的數據經過IoFilterChain里所有配置的IoFilter,IoFilter進行消息的過濾,格式的轉換,在這個層面可以制定一些自定義的協議 
          4.最后IoFilter將數據交給Handler進行業務處理,完成了整個讀取的過程 
          5.寫入過程也是類似,只是剛好倒過來,通過IoSession.write寫出數據,然后Handler進行寫入的業務處理,處理完成后交給IoFilterChain,進行消息過濾和協議的轉換,最后通過I/O Processor將數據寫出到socket通道 
          IoFilterChain作為消息過濾鏈 
          1.讀取的時候是從低級協議到高級協議的過程,一般來說從byte字節逐漸轉換成業務對象的過程 
          2.寫入的時候一般是從業務對象到字節byte的過程 
          IoSession貫穿整個通信過程的始終 
              客戶端通信過程 

             
          1.創建服務器
              package com.gewara.web.module.base;

          import java.io.IOException;
          import java.net.InetSocketAddress;
          import java.nio.charset.Charset;

          import org.apache.mina.core.service.IoAcceptor;
          import org.apache.mina.filter.codec.ProtocolCodecFilter;
          import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
          import org.apache.mina.filter.logging.LoggingFilter;
          import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

          /**
           * Mina服務器
           * 
           * 
          @author mike
           *
           * 
          @since 2012-3-15
           
          */
          public class HelloServer {

                  private static final int PORT = 8901;// 定義監聽端口

                  public static void main(String[] args) throws IOException{
                      // 創建服務端監控線程
                      IoAcceptor acceptor = new NioSocketAcceptor();
                      
                      // 設置日志記錄器
                      acceptor.getFilterChain().addLast("logger", new LoggingFilter());
                      
                      // 設置編碼過濾器
                      acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
                     
                      // 指定業務邏輯處理器
                      acceptor.setHandler(new HelloServerHandler());
                      
                      // 設置端口號
                      acceptor.setDefaultLocalAddress(new InetSocketAddress(PORT));
                      
                      // 啟動監聽線程
                      acceptor.bind();
                  }
          }
           
          2.創建服務器端業務邏輯
              
          package com.gewara.web.module.base;

          import org.apache.mina.core.service.IoHandlerAdapter;
          import org.apache.mina.core.session.IoSession;

          /**
           * 服務器端業務邏輯
           * 
           * 
          @author mike
           *
           * 
          @since 2012-3-15
           
          */
          public class HelloServerHandler extends IoHandlerAdapter {
                   @Override
                  /**
                   * 連接創建事件
                   
          */
                  public void sessionCreated(IoSession session){
                      // 顯示客戶端的ip和端口
                      System.out.println(session.getRemoteAddress().toString());
                  }

                  @Override
                  /**
                   * 消息接收事件
                   
          */
                  public void messageReceived(IoSession session, Object message) throws Exception{
                      String str = message.toString();
                      if (str.trim().equalsIgnoreCase("quit")){
                          // 結束會話
                          session.close(true);
                          return;
                      }
                      
                      // 返回消息字符串
                      session.write("Hi Client!");
                      // 打印客戶端傳來的消息內容
                      System.out.println("Message written" + str);
                  }
          }

          3.創建客戶端
               package com.gewara.web.module.base;

          import java.net.InetSocketAddress;
          import java.nio.charset.Charset;

          import org.apache.mina.core.future.ConnectFuture;
          import org.apache.mina.filter.codec.ProtocolCodecFilter;
          import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
          import org.apache.mina.filter.logging.LoggingFilter;
          import org.apache.mina.transport.socket.nio.NioSocketConnector;

          /**
           * Mina客戶端
           * 
           * 
          @author mike
           *
           * 
          @since 2012-3-15
           
          */
          public class HelloClient {
                 public static void main(String[] args){
                      // 創建客戶端連接器.
                      NioSocketConnector connector = new NioSocketConnector();
                      
                      // 設置日志記錄器
                      connector.getFilterChain().addLast("logger", new LoggingFilter());
                      
                      // 設置編碼過濾器
                      connector.getFilterChain().addLast("codec", 
                              new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8")))); 
                      
                      // 設置連接超時檢查時間
                      connector.setConnectTimeoutCheckInterval(30);
                      
                      // 設置事件處理器
                      connector.setHandler(new HelloClientHandler());
                      
                      // 建立連接
                      ConnectFuture cf = connector.connect(new InetSocketAddress("192.168.2.89", 8901));
                      
                      // 等待連接創建完成
                      cf.awaitUninterruptibly();
                      
                      // 發送消息  
                      cf.getSession().write("Hi Server!");
                     
                      // 發送消息
                      cf.getSession().write("quit");
                      
                      // 等待連接斷開
                      cf.getSession().getCloseFuture().awaitUninterruptibly();

                      // 釋放連接
                      connector.dispose();
                  }
          }

          4.客戶端業務邏輯
          package com.gewara.web.module.base;

          import org.apache.mina.core.service.IoHandlerAdapter;
          import org.apache.mina.core.session.IoSession;

          public class HelloClientHandler extends IoHandlerAdapter {
                  @Override
                  /**
                   * 消息接收事件
                   
          */
                  public void messageReceived(IoSession session, Object message) throws Exception{
                      //顯示接收到的消息
                      System.out.println("server message:"+message.toString());
                  }
          }

          5.先啟動服務器端,然后啟動客戶端
          2012-03-15 14:45:41,456  INFO  logging.LoggingFilter - CREATED
          /192.168.2.89:2691
          2012-03-15 14:45:41,456  INFO  logging.LoggingFilter - OPENED
          2012-03-15 14:45:41,487  INFO  logging.LoggingFilter - RECEIVED: HeapBuffer[pos=0 lim=11 cap=2048: 48 69 20 53 65 72 76 65 72 21 0A]
          2012-03-15 14:45:41,487  DEBUG codec.ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
          Message writtenHi Server!
          2012-03-15 14:45:41,487  INFO  logging.LoggingFilter - SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]
          2012-03-15 14:45:41,487  INFO  logging.LoggingFilter - RECEIVED: HeapBuffer[pos=0 lim=5 cap=2048: 71 75 69 74 0A]
          2012-03-15 14:45:41,487  DEBUG codec.ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 1
          2012-03-15 14:45:41,487  INFO  logging.LoggingFilter - CLOSED

          三:分析源碼
          1.首先看服務器
                      // 創建服務端監控線程
                      IoAcceptor acceptor = new NioSocketAcceptor();
                      
                      // 設置日志記錄器
                      acceptor.getFilterChain().addLast("logger", new LoggingFilter());
                      
                      // 設置編碼過濾器
                      acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
                     
                      // 指定業務邏輯處理器
                      acceptor.setHandler(new HelloServerHandler());
                      
                      // 設置端口號
                      acceptor.setDefaultLocalAddress(new InetSocketAddress(PORT));
                      
                      // 啟動監聽線程
                      acceptor.bind();

            1)先創建NioSocketAcceptor nio的接收器,談到Socket就要說到Reactor模式 
              當前分布式計算 Web Services盛行天下,這些網絡服務的底層都離不開對socket的操作。他們都有一個共同的結構:
          1. Read request
          2. Decode request
          3. Process service                                     
          4. Encode reply
          5. Send reply 

          但這種模式在用戶負載增加時,性能將下降非常的快。我們需要重新尋找一個新的方案,保持數據處理的流暢,很顯然,事件觸發機制是最好的解決辦法,當有事件發生時,會觸動handler,然后開始數據的處理。
          Reactor模式類似于AWT中的Event處理。

          Reactor模式參與者

          1.Reactor 負責響應IO事件,一旦發生,廣播發送給相應的Handler去處理,這類似于AWT的thread
          2.Handler 是負責非堵塞行為,類似于AWT ActionListeners;同時負責將handlers與event事件綁定,類似于AWT addActionListener


          并發系統常采用reactor模式,簡稱觀察者模式,代替常用的多線程處理方式,利用有限的系統的資源,提高系統的吞吐量。

          可以看一下這篇文章,講解的很生動具體,一看就明白reactor模式的好處http://daimojingdeyu.iteye.com/blog/828696 
          Reactor模式是編寫高性能網絡服務器的必備技術之一,它具有如下的優點:
              1)響應快,不必為單個同步時間所阻塞,雖然Reactor本身依然是同步的;
              2)編程相對簡單,可以最大程度的避免復雜的多線程及同步問題,并且避免了多線程/進程的切換開銷;
              3)可擴展性,可以方便的通過增加Reactor實例個數來充分利用CPU資源;
              4)可復用性,reactor框架本身與具體事件處理邏輯無關,具有很高的復用性; 

          2)其次,再說說NIO的基本原理和使用
              NIO 有一個主要的類Selector,這個類似一個觀察者,只要我們把需要探知的socketchannel告訴Selector,我們接著做別的事情,當有事件發生時,他會通知我們,傳回一組 SelectionKey,我們讀取這些Key,就會獲得我們剛剛注冊過的socketchannel,然后,我們從這個Channel中讀取數據,放心,包準能夠讀到,接著我們可以處理這些數據。
            Selector內部原理實際是在做一個對所注冊的channel的輪詢訪問,不斷的輪詢(目前就這一個算法),一旦輪詢到一個channel有所注冊的事情發生,比如數據來了,他就會站起來報告,交出一把鑰匙,讓我們通過這把鑰匙(SelectionKey表示 SelectableChannel 在 Selector 中的注冊的標記。 )來讀取這個channel的內容。










































          posted on 2012-03-15 14:49 陳睿 閱讀(5655) 評論(0)  編輯  收藏 所屬分類: 底層架構


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          導航

          <2012年3月>
          26272829123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統計

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 鄂温| 涞水县| 雷州市| 巴青县| 阳高县| 宁蒗| 许昌县| 福海县| 扬州市| 南江县| 新闻| 天镇县| 北辰区| 吉木萨尔县| 马龙县| 昆明市| 河源市| 博爱县| 嫩江县| 武宁县| 正阳县| 岢岚县| 西乌珠穆沁旗| 宜宾县| 海安县| 平塘县| 潜山县| 札达县| 灵璧县| 元谋县| 塔河县| 定安县| 麦盖提县| 临清市| 金川县| 贡嘎县| 塔河县| 岱山县| 定陶县| 东乡县| 平湖市|