一、 概述
- Openfire最主要的功能是實現XMPP服務器,簡單來說,openfire為我們提供一個固定的地址,我們只需要向openfire服務器發送標准的XMPP信息(即XML文件流),那么openfire服務器應當給予我們回應,這里的openfire服務器也可以看做一個容器,我們在聊天時,需要在這個服務器上注冊一個會話,在會話存在的時間,我們可以實現即時聊天的一些常用功能,比如建立自己的組,添加好友,聊天,以及傳送文件等等,同時,openfire服務器也需要實現自己的管理界面,這樣openfire服務器也扮演一個web容器的角色
- Openfire是開源的實時協作服務器(RTC),它是基於公開協議XMPP(也成為Jabber)消息的。
- 使用它輕易的構建高效率的即時通信服務器。
- Openfire的核心功能可以概括為:連接管理、消息解析、消息路由、消息發送。
- Openfire具有跨平台的能力,Openfire與客戶端采用的是C/S架構,一個服務器要負責為連接在其上的客戶端提供服務。
- Openfire客戶端有spark, pidgin, Miranda IM, iChat等,用戶如果自己開發客戶端,可以采用遵循GPL的開源Client端API--Smack。
- Openfire服務器端支持插件開發,如果開發者需要添加新的服務,可以開發出自己的插件后,安裝至服務器,就可以提供服務,如查找聯系人服務就是以插件的形式提供的。
二、 體系架構
三、 功能模塊
- Pubsub:Publish/Subscribe,這使得xmpp實體能夠在pubsub服務上創建nodes(topics),並且發布信息。一個事件通知將廣播到所有訂閱了這個節點的實體上。
- Pep:(Personal Eventing Protocol)使用XMPP publish-subscribe協議廣播狀態改變事件、及時消息和出席帳戶到其他用戶。
- Stun:為p2p會話提供地址發現服務,如:媒體傳輸和UDP包的收發。
- Router:內部的路由,把相應的包路由給相應的處理器。
- Muc:(Multi-User Chat)用戶可以交換文本信息在room或者channel上下文中,版主或者管理員有權踢除用戶和禁止用戶。
- 所有Module都需要實現Module接口,該接口中定義了模塊生命周期中需要調用的方法
四、 數據模型
- 數據庫表設計:詳見:
- Openfire的數據庫處理采用直接調用JDBC 的方式。核心類為org.jivesoftware.database.DbConnectionManager。數據庫的處理與業務處理耦合,沒有划分出專門的業務邏輯層。
- 3. ConnectionProvider,此類為數據庫提供者接口,如需連接mysql、hsqldb等數據庫,需首先實現些接口,通常直接調用XXManager中的實例方法,XXManager中又調用的是對應的接口XXProvider的方法,實際操作在該接口的實現類中實現。實現類是動態綁定的(默認的實現類通常命名規則為DefaultXXProvider),在運行時根據ofproperty表中對應配置項值選
- org.jivesoftware.database.DbConnectionManager,連接管理類
- org.jivesoftware.util.JiveGlobals,通常用於操作ofproperty表中記錄
- 1. XMPP協議
五、 通信機制
1) XMPP(Extensible Messageing and Presence Protocol:可擴展消息處理現場協議)是目前主流的四種IM(IM:instant messaging,即時消息)協議之一,其他三種分別為:即時信息和空間協議(IMPP)、空間和即時信息協議(PRIM)、針對即時通訊和空間平衡擴充的進程開始協議SIP(SIMPLE)。
2) XMPP的前身是Jabber,一個開源形式組織產生的網絡即時通信協議。
3) 核心的XML流傳輸協議 ,基於XML FreeEIM流傳輸的即時通訊擴展應用,XMPP的擴展協議Jingle使得其支持語音和視頻
4) XMPP協議在PC和Android分別有對應的協議實現smack和asmack,不用我們寫XML協議解析
5) XMPP的基本網絡結構:Client、Server、Gateway,通信能夠在這三者的任意兩個之間雙向發生。服務器同時承擔了客戶端信息記錄,連接管理和信息的路由功能。網關承擔着與異構即時通信系統的互聯互通,異構系統可以包括SMS(短信),MSN,ICQ等。
6) 客戶端利用xmpp(基於TCP/IP)訪問server,傳輸的是XML,工作原理是:
a) 節點連接到服務器;
b) 服務器利用本地目錄系統中的證書對其認證;
c) 節點指定目標地址,讓服務器告知目標狀態;
d) 服務器查找、連接並進行相互認證;
e) 節點之間進行交互
7) XMPP協議的傳輸是通過XML文件來傳輸的,並且不是類似於QQ的點對點通訊,而是客戶端到服務器再到客戶端的方式來實現,以上過程的一個簡單的XMPP通訊流程可以如下:
a) 首先,由客戶端連接到服務器,客戶端通過IO流發送一段XML文件,在文件中包含了自身的用戶名和密碼
b) 服務器端接收到客戶端的XML文件,從中獲取用戶名和密碼進行驗證,如果驗證成功,服務器會發送一個XML文件給客戶端表明已經登錄成功
c) 登陸成功后,客戶端可以通過發送一個獲取好友名單的XML文件,服務器會將當前用戶的好友以XML文件傳到客戶端
d) 客戶端選擇一個好友,向其發送信息(其實是向服務器發送,服務器收到后會轉發給對應的好友),好友收到
8) XMPP地址模式:JID=[ node”@” ] domain [ “/” resource ](如:cyber@cyberobject.com/res),domain:服務器域名,node: 用戶名,resource:屬於用戶的位置或設備。一個用戶可以同時以多種資源與同一個XMPP服務器連接
9) XMPP xml消息格式定義:
<stram>
<presence> //此元素確定用戶的狀態
<status/>
</prensence>
<message> //用於兩個用戶之間發送信息
<body/>
</message>
<iq> //信息/請求,是一個請求-響應機制,管理xmpp服務器上兩個用戶的轉換,允許他們通過相應的xml格式的查詢和響應
<bind/>
</iq>
</stream>
10) XMPP的安全機制:XMPP采用SASL作為身份認證協議,XMPP采用TLS的“START-TLS”擴展來為通信雙方提供加密性和數據完整性服務
11) XMPP體系架構:XMPP server:其內核是一個XMPP路由器,完成基本組件間的數據包交換和路由。功能:1.會話管理器:負責客戶端會話認證,在線狀態,用戶聯系表等;2.數據存儲器(XDB):連接數據庫系統,保持用戶信息、通信日志等;3.連接器管理器:管理與客戶端之間的連接;4.服務器連接器:管理xmpp服務器之間的連接;5.傳輸器:建立xmpp服務器與非xmpp服務器通信
12)
- 2. Apache MINA框架
1) XMPP協議是基於TCP/IP協議進行傳輸的,在openfire中,應用了apache的mina框架作為NIO框架,簡單的來說,openfire服務器用mina框架建立一個簡單的服務器,可以接收和發送基本的IO流,然后在此基礎上把接收到的IO流解析為XML文件,然后在根據XMPP協議對XML文件進行操作
2) 是一個網絡應用程序框架,用來幫助用戶簡單地開發高性能和高可靠性的網絡應用程序。它提供了一個通過Java NIO在不同的傳輸例如TCP/IP和UDP/IP上抽象的事件驅動的異步API,對通信功能進行擴展
3) 為不同的傳輸類型(TCP/UDP)提供了統一的API
4) 過濾器作為一個擴展特性,類似Servlet過濾器
5) 低級(字節緩存)和高級(用戶定義的消息對象和編碼)的API
6) 高度定制化線程模型(單線程/線程池)
7) 超載保護和傳輸流量控制
8) Openfire的ConnectionHandler類繼承了MINA的IoHandlerAdaper,他主要負責連接的創建、銷毀,以及接收到XML數據包的投遞。ConnectionHandler有三個子類,其中ClientConnectionHandler負責客戶端與服務器端的連接,ComponentConnectionHandler負責組件與服務器端的連接,類圖如下:
- 3. Openfire的socket網絡連接
1) 服務器和服務器之間的連接(監聽在端口5269)
2) 外部組件和服務器之間的連接(監聽在端口5275)
3) 多元(complex)連接(監聽在端口5269)
4) 客戶端和服務器的連接(監聽在端口5222)
5) 和客戶端通過TLS/SSL3.0和服務器的連接。(監聽在端口5223)
6) 連接都是通過ConnectionManager接口實現管理的,程序中對ConnectionManager接口的實現類是ConnectionManagerImpl,它是作為一個模塊(Module)類加載到服務器中的
六、 開發配置
- 環境配置:
1) http://blog.csdn.net/kingsonl/article/details/7730225
2) http://blog.csdn.net/nomousewch/article/details/6534555
- 2. Openfire源碼目錄結構
1) build目錄:build目錄下收錄的是生成安裝文件(例如:rpm)所要的一些文件,例如JRE等
2) resources目錄:resources目錄下收錄的是一些為實現國際化(i18n)和本地化的一些編碼文件(例如:英文,中文,法文,德文等)
3) documentation目錄:documentation目錄下收錄的是一些關於Openfire安裝和配置的信息,但最終要的是這里有Openfire開發的Javadoc
4) src目錄:顧名思義這個src文件夾就是我們想要的Openfire源代碼了,這下面又有許多文件夾,我們只要Java文件夾就好,這里面實現的Openfire的核心功能,通過它就可以調試Openfire了
- 3. 命名規則
Openfire中常見的類名后綴命名包括Starter、Plugin、Listener、Dispatcher、Handler、Manager、Provider,通常情況下,這些命名類包括如下意義:
1) XXStarter:系統啟動類
2) XXListener:業務的最終處理類
3) XXDispatcher:調度類,其中有很多關鍵方法,如addListener(),以組合的方式,為類內定義的靜態Set<XXListener>實例添加XXListener對象。以便調用dispatchEvent(String property, EventType eventType, Map<String, Object> params)方法遍歷處理Set集中的XXListener對象(通過調用XXListener對象的各實際方法完成實際業務)
4) XXPlugin:實現Plugin接口的插件類,需實現initializePlugin(PluginManager manager, File pluginDirectory)方法和destroyPlugin()方法。在其初始化方法中調用Dispatcher實現類的addListener()方法如PropertyEventDispatcher.addListener(this)
5) XXProvider:實現面向接口編程方式的接口類,通過反射機制創建具體實現類的對象,反射類名配置在ofproperty表對應的記錄propvalue屬性中。若沒有相關配置,則調用默認實現類,默認實現類類名命名規則為DefaultXXProvider
6) XXHandler:實際處理類,以ConnectionHandler為例,在org.jivesoftware.openfire.spi. ConnectionManagerImpl類的startClientSSLListeners(String localIPAddress)方法中,有這樣一段代碼:sslSocketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));其中bind方法的第二個參數是新創建的一個ClientConnectionHandler的實例,而它就是ConnectionHandler的一個子類
- 4. 系統配置
Openfire的系統配置項采用文件結合數據庫表的方式配置,也有部分默認配置項通過Java硬編碼方式配置(如org.jivesoftware.openfire. ConnectionManager接口類中定義的DEFAULT_PORT、DEFAULT_SSL_PORT、DEFAULT_COMPONENT_PORT等),Openfire中比較重要的配置位置包括:
1) src/conf目錄下的openfire.xml配置文件。該配置文件為系統核心配置文件。在第一次啟動Openfire並通過管理控制台完成安裝配置后會往該配置文件中填入相應的配置信息
2) plugin.xml配置文件。該配置文件為各插件包下的核心配置文件,由它確定插件核心處理類和相應頁面插件的展現等。配置項及含義詳見官方插件開發說明部分
3) web.xml和web-custom.xml配置文件。用於配置servlet和用戶自定義servlet(插件頁面用,放在插件對應目錄下)
4) ofproperty中的各條記錄,該表中包括兩個字段name和propvalue,分別代表配置項名和配置項值
- 5. Openfire啟動過程
系統啟動時調用org.jivesoftware.openfire.starter.ServerStarter類中的start()方法,加載org.jivesoftware.openfire.XMPPServer類,並調用這個類的start(),Start()方法中首先調用verifyDataSource()方法驗證並確保數據庫可以訪問,然后會調用 loadModules();initModules();startModules();方法來對Module接口的實現類的各子類進行操作,依次完成模塊的加載、初始化和啟動操作。loadModules()方法中會調用loadModule(String module)方法通過反射加載各模塊類,參數字符串module為對應的模塊核心處理類的類名
- 6. 消息處理流程
在Openfire服務器對XMPP的實現中,消息被封裝為Packet對象,因此Openfire服務器的核心代碼是對客戶端Packet對象的監聽和處理流程
Packet處理流程:
1) 首先,Openfire服務器需要啟動一個基於TCP/IP的監聽服務,用以接收客戶端傳過來的XML流文件。這個過程在XMPPServer類的start()方法中進行,這個監聽服務是以loadModule(ConnectionManagerImpl.class.getName())來加載,調用ConnectionManagerImpl類的createClientListeners()方法
2) 其中的socketAcceptor是在buildSocektAcceptor()方法中定義的,它是作為一個服務端的接收器,是mina框架為我們封裝好的一個socketserver,在上面這個方法中,我們為socketAcceptor添加了一個過濾器,XMPPCodeFactory,這個類將過濾xmpp相關請求,加以處理,我們再看同一個類的另外一個方法startClientListener()
3) 其中的socketAcceptor.bind()方法啟動了監聽服務器,來監聽所有發送到服務器5222端口的數據,並用ClientConnetionHandler類來處理,ClinetConnectionHandler繼承於ConnectionHandler類,后者實現了mina的IoHandlerAdaptor接口,其中的messageReceived()方法是關鍵
4) 可以看到收到的信息交由StanzaHandler的process方法中進行XML解析並封裝為packet對象,然后再進行下一步的處理,至此,從客戶端到服務器端的packet傳遞結束,如下圖所示:
- 7. Spark 登錄過程-安全認證
1) Spark登錄過程消息截圖:
2) Spark登錄過程中的XMPP消息含義:
- 8. WEB服務器
1) Openfire采用內置的jetty作web服務器,在啟動AdminConsolePlugin插件時調用startup()方法啟動jetty服務器,9090為其明文端口,9091為其加密端口
2) Openfire沒有采用現在很流行的技術架構(SSH),只使用JSP+JavaBean,但是它有自己的系統設計,就連日志都是自己做的,沒有使用我們熟悉的log4j
3) 現有的Openfire管理控制台可采用插件方式進行擴展,頁面采用Jsp方式實現,頁面直接調用業務處理邏輯類(通常命名為XXManager)的實例方法,通常通過request對象封裝的方式傳遞頁面展現判定變量,常出現本頁跳轉。每個插件可定義自己的Servlet類和web.xml及web-custom.xml配置文件
4) 頁面展現采用裝飾框架方式,decorator頁面有兩個,即src/web/decorators目錄下的兩個頁面main.jsp和setup.jsp。采用自定義的admin標簽實現,標簽庫admin.tld放置在src/web/WEB-INF目錄下,標簽解析類放置在org.jivesoftware.admin包下,有SidebarTag、SubnavTag、SubSidebarTag、TabsTag四個解析類。在調用loadPlugin()方法進行插件加載時,解析插件的plugin.xml配置文件,將獲取的相關信息封裝在AdminConsole類的generatedModel對象中,后期通過插件解析類提取該對象中的數據並配合sitemesh裝飾器進行頁面展現。
社交app實戰如下圖:
溝通聯系qq:2729404527 微信:code588