Openfire階段實踐總結

来源:http://www.cnblogs.com/5207/archive/2016/06/02/5552726.html
-Advertisement-
Play Games

從3月開始研究Openfire,其實就是要做一套IM系統,也正是這個原因才瞭解到Openfire。之前還真沒想過有這麼多的開源產品可以做IM,而且也沒想到XMPP這個協議竟然如何強大。看來還是標準為先,好的標準可以推動產業發展啊。 Openfire的搭建與簡單的demo之前寫過篇《技術筆記:XMPP ...


從3月開始研究Openfire,其實就是要做一套IM系統,也正是這個原因才瞭解到Openfire。之前還真沒想過有這麼多的開源產品可以做IM,而且也沒想到XMPP這個協議竟然如何強大。看來還是標準為先,好的標準可以推動產業發展啊。

 

Openfire的搭建與簡單的demo之前寫過篇《技術筆記:XMPP之openfire+spark+smack》,當時主要關註的怎麼讓這套體系跑起來吧,只不過現在還是在這個階段,只是多學了點東西留下點筆記吧。

 

1、對於XMPP的學習很重要

最開始覺得搭建一套Openfire+spark太簡單啦,而且將spark的界面修改一下就可以變成一個新的產品,所以當時覺得XMPP協議這麼高深的東西不用太深入。只不過隨著簡單的事情結束了才發現,最核心的還是協議本身,瞭解協議可以更瞭解系統的運作,才能體會到這套系統是有多複雜。當然是對於我來說有點複雜,特別是涉及到前後端結合設計與開始時。

為此我推薦一個國內的XMPP協議翻譯網站:http://wiki.jabbercn.org/%E9%A6%96%E9%A1%B5。

當然如果英文好那就原版吧:http://xmpp.org/about/technology-overview.html

經過一段時間學習後,感覺QQ和微信在基礎原理上真的和XMPP很類似,只是使用的協議格式有些差別,或許這就是即時通訊的抽象層次吧。但是使用XML這種標記語言是不是很浪費流量呢?雖然XMPP擴展起來非常方便,但是就這些標簽也著實夠大的,像平常的文字聊天時,或許中間標記產生的流量也和聊天內容相當了。畢竟我還沒到這種需要考慮大流量的階段,所以這隻是一個想法而已。

2、Openfire的一些設計點與思路

Openfire的源代碼整體看了看還是比較清晰的,擴展上支持插件與組件模式。在最近擴展的中發現openfire的源代碼本身不太好去修改,依賴性很強,唯獨模塊間的依賴比較鬆散些,模塊內的類依賴基本是緊耦合的。只不過Openfire可以通過插件擴展,對源代碼本身的依賴就小了許多,所以說整體來說還是很不錯的。

在Openfire中的插件擴展方式主要是:

  • IQHandler

在XMPP協議中IQ包是指的信息/查詢,可以用於伺服器與客戶端之間進行數據查詢,Openfir中實現了一個IQRouter來處理IQ包。自然IQHandler就是具體的IQ包處理單元啦。IQHandler是基於namespace來進行攔截處理的,自定義自己的命名空間後即可。

IQHandler提供了兩個抽象方法,用於派生類實現:

    /**
     * Handles the received IQ packet.
     *
     * @param packet the IQ packet to handle.
     * @return the response to send back.
     * @throws UnauthorizedException if the user that sent the packet is not
     *      authorized to request the given operation.
     */
    public abstract IQ handleIQ(IQ packet) throws UnauthorizedException;

    /**
     * Returns the handler information to help generically handle IQ packets.
     * IQHandlers that aren't local server iq handlers (e.g. chatbots, transports, etc)
     * return <tt>null</tt>.
     *
     * @return The IQHandlerInfo for this handler
     */
    public abstract IQHandlerInfo getInfo();

handleIQ方法就是解包和業務處理過程,最後返回結果包。

getInfo是用於返回當前IQHandler的命令空間

然後要使這個handler生效還需要註冊到IQRouter,可以在插件啟動時創建IQHandler的對象並add進去:

@Override
    public void initializePlugin(PluginManager manager, File pluginDirectory) {
        iqHandler = new IQGroupChatHander();
        iqRouter = XMPPServer.getInstance().getIQRouter();
        iqRouter.addHandler(iqHandler);
    }

    @Override
    public void destroyPlugin() {
        iqRouter.removeHandler(iqHandler);
    }

 

  • Compoent

Compoent也是一種比較常用的擴展方法,可以通過對特定子域的包進行處理。比如MUC通過註冊不同的Service,每個Service都有一個subdomain,系統會將不同的subdomain的數據包分發到專門服務中處理。這樣就帶來了一個好處,可以完全自定義一套子域的包處理業務,後面實現公眾號訂閱號就想通過這種思路來解決。而且Openfire還有遠程組件的機制,可以擴展成為一個獨立的業務系統,這樣openfire可以只充當消息處理的核心。

具體的應用也比較簡單,實現Component介面,並註冊到ComponentManager中。而Component介面中最為重要的方法就是processPacket方法,代碼如下:

    /**
     * Processes a packet sent to this Component.
     *
     * @param packet the packet.
     * @see ComponentManager#sendPacket(Component, Packet)
     */
    public void processPacket(Packet packet);

註意方法中的參數是Packet,這個表示所有子域下的通訊原語都可以用於這裡處理。

註冊與退出的方法如下:

       componentManager = ComponentManagerFactory.getComponentManager();
        try {
            componentManager.addComponent("subdomain", this);
        }
        catch (Exception e) {
            Log.error(e.getMessage(), e);
            System.err.println(e);
        }

        try {
            componentManager.removeComponent("subdomain");
        } catch (ComponentException e) {
            Log.error(e.getMessage(), e);
        }
  • PacketInterceptor

在Openfire中所以的傳輸都是基於packet,在packet上再派生出不同的通訊原語,如message、roster、JID、IQ等等。基於這個原理只要提供一套對於包的攔截機制就可以實現一套比較強大的擴展機制。在Openfire中就提供了這樣的機制處理。在IQRouter\PresenceRouter\MessageRouter中都提供了對於包的攔截器。

// Invoke the interceptors before we process the read packet
            InterceptorManager.getInstance().invokeInterceptors(packet, session, true, false);

攔截器都註冊在InterceptorManager中,在路由處理包時都會調用攔截器,上面的代碼就是在路由中截取的代碼例子。

那麼同樣的實現一個攔截器PacketInterceptor介面,並註冊到InterceptorManager即可。

InterceptorManager.getInstance().addInterceptor(interceptor);

InterceptorManager.getInstance().removeInterceptor(interceptor);

 

有了以上三種方法,Openfire可以發展出各種用法,所以官方自己也實現了放多插件供使用。在此也建議對於openfire的擴展最好還是使用插件吧,除非自己的定製要求很高,Openfire本身已經不適應了的。

我的要求基本都可以達成,而且這樣以後升級新版本也非常簡單,不會出現問題。

3、Spark的糾結

Spark同樣出自於jivesoftware,但感覺擴展上就不那麼好了。也許是我沒有完全弄明白它的擴展原理吧。其實我的需求是重寫Spark的UI,同時加入自己的功能,比如群、訂閱號等。最開始想著Spark也是支持插件的,但是最後改代碼時才發現,裡面依賴太深了,基本上和界面相關的都存在依賴,最後可能都要重寫一套。

其實在Spark中是有一個UIComponentRegistry類的,一些主要的界面都在這個類中註冊的。但可惡的是這些註冊的類大多都不能派生出新類來替換這些註冊的類。比如

private static Class<? extends ChatRoom> chatRoomClass = ChatRoomImpl.class;

這是聊天視窗的註冊類,那麼如果我想寫一個自己的聊天視窗,是不是直接把這個註冊類替換即可呢?不行,因為在其他代碼會盡然會這樣使用

    @Override
    public void filesDropped(Collection<File> files, Component component) {
    if (component instanceof ChatRoomImpl) {
        ChatRoomImpl roomImpl = (ChatRoomImpl) component;

        for (File file : files) {
        SparkManager.getTransferManager().sendFile(file,
            roomImpl.getParticipantJID());
        }

        SparkManager.getChatManager().getChatContainer()
            .activateChatRoom(roomImpl);
    }
    }

在另一個類里盡然直接使用派生類進行了類型判斷,這還只是一個點,類似的點太多了。所以最開始想著通過派生UIComponentRegistry中註冊的類來達到預期目的已經不大可能了。再加上時間有限,也就懶得管這麼多了,就讓開發直接在源代碼上改。

 

可惡的是2.7.7版本升級時發現代碼大變,這個版本升級smack4.x版本,而且大量使用了1.8的新特性。所以又經過了一番代碼合併才升級上來。另外說到smack基本不提供擴展,只提供事件的訂閱。

只不過spark是跨平臺的,很容易就能在mac下運行,而且代碼是java的,暫時還不想拋棄掉,等將來考慮是不是再重寫吧。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 常用快捷鍵 自動生成頭部註釋 代碼片段 NuGet Team Foundation 常用的VS快捷鍵 查看與設置快捷鍵 一般在菜單裡面我們直接就可以看到一些功能的快捷鍵。另外,可以依次通過 菜單欄-工具-選項-環境-鍵盤 中查看和設置對應功能的快捷鍵 推薦幾個我比較常用的快捷鍵 我用的是VS2015 ...
  • 1、頁面後臺代碼添加如下靜態變數: 2、在處理數據的開始,初始化total和startTime變數: 3、在處理數據過程中,不斷累加cur: 4、前端每隔200毫秒獲取進度: 5、後臺計算進度: 效果圖(文字錯了,不是“導入進度”,而是“數據處理進度:”): ...
  • 公司業務量比較大,接了很多項目,為了縮短開發周期老闆讓我牽頭搭建了一個敏捷開發框架。 我們主要的業務是做OA、CRM、ERP一類的管理系統,一個通用的後臺搭出來,再配合一些快速開發的組件開發效率能提高很多。 另外老闆一再強調要支持APP開發,一次開發能部署到安卓和IOS上。 作為開篇之作,先介紹一下 ...
  • 定製路由系統 路由系統是靈活可配置的,當然還可以通過下麵這兩種方式定製路由系統,來滿足其他需求。 1、 通過創建自定義的RouteBase實現; 2、 通過創建自定義路由處理程式實現。 創建自定義的RouteBase實現 創建自定義的RouteBase實現,需要實現一個RouteBase的派生類,而 ...
  • 同Winsock1相比,Winsock2最明顯的就是支持了Raw Socket套接字類型,使用Raw Socket,可把網卡設置成混雜模式,在這種模式下,我們可以收到網路上的IP包,當然包括目的不是本機的IP包,通過原始套接字,我們也可以更加自如地控制Windows下的多種協議,而且能夠對網路底層的 ...
  • 在上一篇文章中我們主要分析了ASP.NET Core預設依賴註入容器的存儲和解析,這一篇文章主要補充一下上一篇文章忽略的一些細節:有關服務回收的問題,即服務的生命周期問題。有關源碼可以去GitHub上找到。 這次的主角就是ServiceProvider一人,所有有關生命周期的源碼幾乎都集中在Serv ...
  • 相信很多人用過MessageBox.show(),是不是覺得這個消息框有點醜呢,反正我是覺得有點醜的,所以我自己重寫了一個。先不說,上兩幅圖對比先: 當然,也不是很好看,不過比原有的好多了。 不多說了,先上xmal代碼: 1 <Window x:Class="MESBox.MEGBox" 2 xml ...
  • 在Web Form 情況下,每一個 ASPX頁面既是一個文件,又是一個隊請求自包含的響應。而在 MVC 情況下,請求是由控制器類中的動作方法處理的,而且與硬碟上的文件沒有一對一的相互關係。 ASP.NET 平臺為了處理 MVC 的 URL,採用了路由系統,它主要有兩個功能: 考查一個輸入 URL(I ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...