Socket通訊封裝MIna框架–含羞代放

  • 2019 年 10 月 3 日
  • 筆記

Mina非同步IO使用的Java底層JNI框架,Mina提供服務端和客戶端,將我們的業務解耦開發.真正做到高內聚低耦合的思想

核心類

  • IoService :Mina中將服務端和客戶端都看成是服務,這裡提供統一介面IoService,這個介面的作用就是用來處理套接字機制。也正是IoService來監聽消息返回消息這些步驟,
    可以說IoService就是我們Mina中核心

  • IoProcessor:這個介面在另一個執行緒上,負責檢查是否有數據在通道上讀寫,也就是說它也擁有自己的Selector,這是與我們使用JAVA NIO 編碼時的一個不同之處,通常在JAVA NIO 編碼中,我們都是使用一個Selector,也就是不區分IoService與IoProcessor 兩個功能介面。另外,IoProcessor 負責調用註冊在IoService 上的過濾器,並在過濾器鏈之後調用IoHandler

  • IoFilter : 定義了一些攔截器 , 和我們web中攔截器一樣,用來橫向攔截處理一些全局的操作(日誌處理,編碼處理)。其中我們必須注意的是加解密消息。
    作為一個好的框架肯定是有默認的攔截器的(TextLineCodecFactory )。默認攔截器可以叫消息強制轉換為String類型。畢竟String最通用

  • IoHandler : 這個是我們處理消息的邏輯,前面的攔截器只是在接受是進行一些驗證、翻譯的功能。拿到數據之後我們需要做的事情就是在IoHandler中

各個擊破

IoService

  • 首先我們已服務端NioSocketAcceptor為列,看看我們的服務類之間的結構依賴關係
    NioSocketAcceptor結構圖

  • IoService是服務的鼻祖,無論在我們看來的服務端還是客戶端都得繼承它(間接繼承)。在IoService中我們會定義我們消息的處理過濾器(上文的攔截器),消息處理的業務類
    在上文簡介中我們知道,這一步其實是IoProcessor來完成,那麼IoProcessor在什麼出現呢。比如Mina框架中用來創建服務端類NioSocketAcceptor。他直接繼承了AbstractPollingIoAcceptor。而AbstractPollingIoAcceptor類中根據參數創建了我們需要的IoProcessor.從而我們有了IoProcessor就可以執行消息間的通訊了。
    IoProcess的產生

  • 所以過濾器、處理器實在我們服務啟動之前配置好的。一旦啟動成功就無法再修改了。我們服務端NioSocketAcceptor通過bind方法就可以綁定到指定埠上。我們這裡的綁
    定實現了多態綁定。我們可以綁定多個服務。

  /**  * {@inheritDoc}  */  @Override  public final void bind(Iterable<? extends SocketAddress> localAddresses) throws IOException {      if (isDisposing()) {          throw new IllegalStateException("The Accpetor disposed is being disposed.");      }        if (localAddresses == null) {          throw new IllegalArgumentException("localAddresses");      }        List<SocketAddress> localAddressesCopy = new ArrayList<>();        for (SocketAddress a : localAddresses) {          checkAddressType(a);          localAddressesCopy.add(a);      }        if (localAddressesCopy.isEmpty()) {          throw new IllegalArgumentException("localAddresses is empty.");      }        boolean activate = false;      synchronized (bindLock) {          synchronized (boundAddresses) {              if (boundAddresses.isEmpty()) {                  activate = true;              }          }            if (getHandler() == null) {              throw new IllegalStateException("handler is not set.");          }            try {              Set<SocketAddress> addresses = bindInternal(localAddressesCopy);                synchronized (boundAddresses) {                  boundAddresses.addAll(addresses);              }          } catch (IOException | RuntimeException e) {              throw e;          } catch (Exception e) {              throw new RuntimeIoException("Failed to bind to: " + getLocalAddresses(), e);          }      }        if (activate) {          getListeners().fireServiceActivated();      }  }

在上面我們可以看到bind最後是去激活對應的監聽器。我們一個IoServer處理一個執行緒中的消息。我們監聽器就是監聽執行緒內的消息。每一次的綁定都會有不同的監聽器、ioSession去專門處理消息之間的通訊。我們可以通過IoSession設置一些請求數據完成數據的許可權驗證。

  • 在服務創建的時候我們正常需要設置IoSession的一些配置。通過getSessionConfig方法獲取IoSessionConfig。裡面設置參數常用如下:
    • setReadBufferSize : 設置讀取數據的緩衝區大小
    • setMinReadBufferSize: 設置緩衝區最大值
    • setMaxReadBufferSize: 設置緩衝區最小值
    • setThroughputCalculationInterval: 設置通道計算時間 默認3s
    • setIdleTime(IdleStatus status, int idleTime): status 設置是一方還是雙方 , idLetime 是超過多久就會進入空閑狀態
IoAcceptor acceptor=new NioSocketAcceptor();  acceptor.getSessionConfig().setReadBufferSize(2048);  acceptor.getSessionConfig.setIdleTime(IdleStatus.BOTH_IDLE,10);

IoFilter

在IoService中有獲取filter鏈的一個方法 DefaultIoFilterChainBuilder getFilterChain() , 我們需要做的就是定義過濾器,然後通過該方法獲取過濾鏈加入到請求鏈上。
我們自定義過濾器也很簡單,只需要繼承IoFilterAdapter這個類就好了。

  acceptor.getFilterChain().addLast("codec",  new ProtocolCodecFilter(new TextLineCodecFactory(  Charset.forName("UTF-8"),LineDelimeter.WINDOWS.getValue(),LineDelimiter. WINDOWS.getValue()))  );    

TextLineCodecFactory 這個類是Mina提供的編解碼工廠,這個工廠的特性是以換行符’rn’為結束通訊的標誌。也就是說如果我們傳遞消息沒有換行符,另外一段會繼續
接受消息知道接受到’rn’才會接受,並把接受到的消息通過編解碼器轉到IoHandler層供業務層處理。(這裡部落客被坑在這裡了)

IoHandler

  • 到了這一步,我們的通訊基本就已經完成了。剩下的事情已經和Mina基本沒多大關聯了。我們將在這裡處理業務邏輯,使用到的就是Handler提供的接收消息和發送消息兩個功能。
    這裡我們需要注意的是Handler提供messageReceivedmessageSent並不是字面意思。前者就是消息的接受,但是後者並不是消息的發送。我們常用的發送消息是session.write方法。

總結

今天我們了解了Mina工作的流程,主要就是IoFilter和IoHandler實現消息的通訊 。 千里之行始於足下,一點一點的進步。下面貼出一份總結的圖譜幫助我們理解Mina流程

Mina流程

加入戰隊

# 加入戰隊

微信公眾號

微信公眾號