XMPP客戶端庫Smack 4.0.6版開發之一

1、Smack庫概述html

Smack是一個開源、易用的XMPP/Jabber客戶端庫,它使用Java語言開發,由Jive Software開發。java

Smack的優勢是編程簡單。git

Smack的缺點是其API並不是爲大量併發用戶設計,每一個客戶都要1個線程,佔用資源相對較,所以用Smack作模擬測試時,1臺機器只能模擬有限(數千個)客戶。github

截止2014年11月27日,Smack庫已經發展到4.0.6版。編程

最新的好消息是Smack在4.1.0版後將直接支持Android系統,而無需再使用之前的Smack移植版aSmack庫了。安全

Smack庫源碼託管於GitHub,主頁見: https://github.com/igniterealtime/Smack/服務器



2、Smack 4的改變併發

Smack庫從3.4版發展到4.0.x版後,其API有較大的變化,主要有:ide

一、把Connection類重命名爲XMPPConnection類測試

XMPPConnection類是XMPPTCPConnection類和XMPPBOSHConnection類的父類。

二、把各類Provider類進行了分包

三、keep-alive(持久鏈接)機制從smack-core庫移到了smack-extensions庫

keep-alive機制如今由PingManager類提供。

四、PrivacyList類的toString()方法重命名爲getName()

五、當Chat實例的全部引用都撤掉後,應該調用Chat.close()方法

不然Chat對象會有內存泄露的隱患,直到ChatManager對象被垃圾回收器回收後內存泄露隱患纔會消失。

六、ServerTrustManager類被移除了

若是要使用帶SSL認證的XMPP,你只需提供本身的SSLContext對象給ConnectionConfiguration對象便可。

七、Packet.setProperty()從smack-core庫移到了smack-extensions庫

其API如今能夠在org.jivesoftware.smackx.jiveproperties包中找到。

八、Connection.getAccountManager()方法如今改爲了AccountManager.getInstance(XMPPConnection)方法

九、異常API作了改進

十、ToContains過濾器被移除了

3、Smack庫的特徵
一、極度簡單易用,API功能強大
發送一條文本消息給某個用戶只需幾行代碼:

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker""password""jabber.org");  

  2. connection.connect();  

  3. connection.login();  

  4. Chat chat = ChatManager.getInstanceFor(connection)  

  5.         .createChat("jsmith@jivesoftware.com"new MessageListener(){  

  6.     public void processMessage(Chat chat, Message message){  

  7.         System.out.println("Received message: " + message);  

  8.     }  

  9. });  

  10. chat.sendMessage("Howdy!");  


二、隔離了底層數據包組裝的複雜性,天然有相應的庫來完成這些功能。Smack提供了更智能的高層構造,好比Chat類和Roster類,這樣開發會更富有效率。
1)無需熟悉XMPP的XML格式,甚至都不須要了解XML
2)提供了簡單的M2M通訊
Smack讓開發者能夠對每條消息都設置大量的屬性,屬性中還能夠包含Java對象。
3)基於Apache許可證的開源代碼,這意味着你能夠把Smack放入你本身的商業軟件中。

4、Smack庫的組成
Smack庫能夠內嵌到任意的Java應用程序中。Smack庫有數個JAR文件組成,很是具備靈活性。
一、smack-core.jar
提供了核心XMPP功能。都是XMPP RFC規範定義的XMPP特性。
二、smack-extensions.jar
支持許多由XMPP Standards Foundation定義的擴展(XEP)功能。包括羣聊、文件傳輸、用戶搜索等等。
之後可查看文檔《擴展手冊》:
https://github.com/igniterealtime/Smack/blob/master/documentation/extensions/index.html
(目前仍是無效的)
三、smack-experimental.jar
支持許多由XMPP Standards Foundation定義的體驗性(XEP)功能。其API和功能特性都被認爲是不穩定的。
四、smack-legacy.jar
支持許多由XMPP Standards Foundation定義的遺留(XEP)功能。
五、smack-bosh.jar
支持BOSH通訊(XEP-0124規範定義的)。此代碼被認爲處於Beta階段。
六、smack-jingle.jar
支持Jingle。此代碼很老,目前處於無維護的狀態。
七、smack-resolver-dnsjava.jar
支持對DNS SRV記錄的解析,主要用於那些不支持javax.naming API的平臺。
八、smack-debug.jar
用於協議流量的加強型GUI調試器。當調試模式開啓後,若是它在類路徑下,它會自動被使用。
之後可查看文檔《調試模式》:
https://github.com/igniterealtime/Smack/blob/master/documentation/debugging.html
(目前仍是無效的)

5、Smack的配置
Smack的初始化過程涉及到2階段的調用。
一、初始化系統屬性
經過SmackConfiguration類初始化全部的系統可訪問屬性,這些屬性都是經過getXXX方法取回屬性值的。
二、初始化啓動類
任意類若是繼承了SmackInitializer接口後,均可以在調用initialize()方法後獲得初始化,這意味着獲得初始化的類在啓動後都是活動的。
若是沒有繼承SmackInitializer接口,那麼要實現初始化,必需要放置一個靜態代碼塊來實現——他在類裝載時會自動執行。

初 始化是經過配置文件來完成的。默認狀況下,Smack會載入Smack JAR文件中內嵌的配置文件(它位於org.jivesoftware.smack/smack-config.xml)。這個指定的配置文件包含了一系 列需載入初始化的類列表。全部的管理器類型的類都須要被初始化,這些管理器類就包含在上面所說的初始化列表中。

6、創建鏈接的例子

XMPPConnection類用於建立一個到XMPP服務器的鏈接,代碼例子以下:

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. // 建立一個到jabber.org服務器的鏈接  

  2. AbstractXMPPConnection conn1 = new XMPPTCPConnection("username""password""jabber.org");  

  3. conn1.connect();  


[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. // 建立一個到jabber.org服務器指定端口的鏈接  

  2. XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()  

  3.         .setUsernameAndPassword("username""password")  

  4.         .setServiceName("jabber.org")  

  5.         .setHost("earl.jabber.org")  

  6.         .setPort("8222)  

  7.         .build();  

  8. AbstractXMPPConnection conn2 = new XMPPTCPConnection(config);  

  9. conn2.connect();  


注意,在鏈接到XMPP服務器時,若是採用默認設置,會使用最大程度的安全,包括TLS加密的應用。ConnectionConfiguration類經過了對建立的鏈接的高級控制,好比能夠開啓或關閉加密。
之後可查看文檔《XMPPConnection Management》:
https://github.com/igniterealtime/Smack/blob/master/documentation/connections.html
(目前仍是無效的)

一旦你建立了一個鏈接後,你應該調用XMPPConnection.login()方法進行服務器登陸。一旦登陸後,你就能夠經過建立Chat對象或GroupChat對象開始與其餘用戶聊天了。

7、Roster(名單)的用法

Roster用於跟蹤其餘用戶是否在線。用戶的聯繫人能夠以分組的方式進行組織,好比「好友」、「同事」。而後就能夠查看組中的每一個用戶是否在線了。
要檢索Roster,使用XMPPConnection.getRoster()方法。Roster類容許你查找全部的Roster實體,以及他們屬於哪一個組,每一個實體當前的在線狀態。

8、讀寫Packet(數據包)

從 客戶端發送到XMPP服務器的每一條消息都稱爲一個Packet(數據包)。org.jivesoftware.smack.packet庫中包含了 XMPP支持的(消息Message、在線狀態Presence、IQ)三種不一樣的基本數據包類型的封裝類。而像Chat或GroupChat這樣的類則 提供了更高層的結構來管理數據包的自動建立和發送。可是,開發者仍是能夠直接建立和發送數據包的。
下面的代碼就是修改本身的在線狀態,讓其餘人知道你不在線。

[java] view plaincopyprint?在CODE上查看代碼片派生到個人代碼片

  1. // 建立新在線狀態對象,並設爲離線狀態  

  2. Presence presence = new Presence(Presence.Type.unavailable);  

  3. presence.setStatus("Gone fishing");  

  4. // 發送數據包(假設咱們已經有XMPPConnection的鏈接實例con  

  5. con.sendPacket(presence);  


Smack提供了兩種讀取到來的數據包的方式:PacketListener(包監聽器)和PacketCollector(包收集器)。
二者都使用PacketFilter實例來判斷應該處理哪個數據包。
PacketListener(包監聽器)用於事件風格的編程,而PacketCollector(包收集器)有一個數據包的結果隊列,你能夠作輪詢或阻塞等操做。
也就是說,若是你想在數據包到來時執行一些動做,那麼包監聽器很適合。若是你想等待指定的數據包的到來,那麼包收集器很適合。
包收集器和包監聽器都使用Connection鏈接實例建立。

3、XMPPConnection管理

一、建立鏈接

org.jivesoftware.smack.XMPPConnection類可管理到XMPP服務器的鏈接,它默認的鏈接實現類是org.jivesoftware.smack.XMPPTCPConnection。它主要使用兩個構造方法,

一個是XMPPTCPConnection(StringserverName)方法,參數爲服務器名。鏈接會使用全部默認的設置,有:

1)執行DNSSRV查詢,找到服務器確切的地址和端口(一般是5222)。

2)與服務器協商最大數安全,包括TLS加密。但若是有必要,鏈接會回落到較低的安全設置。

3)XMPP資源名「Smack」會被用於鏈接。

第二個是XMPPTCPConnection(ConnectionConfigurationcc)構造器,它會指定高級的鏈接設置。其中包括:

1)手動指定服務器地址和端口,而不是經過DNSSRV查詢。

2)能開啓鏈接壓縮。

3) 指定自定義的鏈接資源名(如Work或Home)。用戶到服務器的每個鏈接都必須有惟一的資源名。好比對於用 戶"jsmith@example.com",完整的帶資源的地址應該是"jsmith@example.com/Smack"。經過攜帶惟一的資源名, 用戶能夠同時從不一樣的位置登陸到同一個服務器,這適用於多設備的狀況。

每個資源使用的在線優先級值:用於決定由哪個帶資源的指定鏈接來接收到裸地址"jsmith@example.com"的消息。

 

二、鏈接和關閉鏈接

//爲新鏈接建立配置

ConnectionConfigurationconfig = new ConnectionConfiguration(「jabber.org」, 5222);

AbstractXMPPConnectionconn = new XMPPTCPConnection(config);

//鏈接到服務器

conn.connect();

//登陸到服務器

conn.login(「username」,「password」,「SomeResource」);

 

//關閉鏈接

conn.disconnect();

 

默認狀況下,一旦鏈接斷開,Smack會嘗試重建鏈接。

使用ConnectionConfiguration類的setReconnectionAllowed(Boolean)方法能夠開啓或關閉重連的功能。

重連管理器會當即嘗試重連到服務器,而且會增長延時設置,以便提升重連的成功率。

在重連管理器正在等待下一次重連的期間,若是你想強制重連,可使用AbstractXMPPConnection類的connect()方法,它會嘗試創建一個新鏈接。若是手動嘗試也失敗了,那麼重連管理器會繼續重連的工做。

4、使用Chat消息通訊

來回收發消息是即時通訊的核心功能。儘管單條消息是以包的形式發送和接收的,一般仍是把他視爲聊天的消息字符串,使用org.jivesoftware.smack.Chat類。

一、Chat類

一個聊天Chat會在兩個用戶之間建立一個消息線程(經過線程ID)。下面的代碼片斷演示了怎樣建立一個新聊天,而後向用戶發送一條文本消息:

//假設已經建立了一個名爲"connection"的XMPPConnection

ChatManagerchatmanager = connection.getChatManager();

ChatnewChat = chatmanager.createChat("jsmith@jivesoftware.com", newMessageListener(){

    public void processMessage(Chat chat,Message message){

        System.out.println(「Receivedmessage: 「+ message);

    }

});

try{

    newChat.sendMessage(「Howdy!」);

}catch(XMPPExceptione){

    System.out.println(「Error Deliveringblock」);

}

 

Chat.sendMessage(String) 方法能夠方便地建立一個消息Message對象,用字符串參數設置消息正文Body,而後發送消息。在某些狀況下你可能但願在發送消息前設置額外的值,使 用Chat.createMessage()方法和Chat.sendMessage(Message)方法,以下面的代碼片斷所示:

MessagenewMessage = new Message();

newMessage.setBody(「Howdy!」);

message.setProperty(「favoriteColor」,「red」);

newChat.sendMessage(newMessage);

 

前面的例子中,咱們能夠注意到,在建立聊天Chat時指定了一個消息監聽器MessageListener,在任意時刻,當來自其它用戶的聊天消息到達後,消息監聽器會獲得通知。下面的代碼片斷使用了監聽器作鸚鵡學舌,它會回顯來自其餘用戶傳遞的消息。

//假設在聊天Chat中已經設置了消息監聽器MessageListener

publicvoid processMessage(Chat chat, Message message){

    // 把用戶發送的消息內容發送給用戶

    chat.sendMessage(message.getBody());

}

 

二、來電聊天

當 提示有另外一個用戶的聊天消息到了後,設置有輕微的不一樣,由於你是首次接收到聊天消息。取代明確地建立一個Chat來發送消息,當ChatManager創 建了Chat實例後,你須要註冊處理新建立的Chat實例。ChatManager會經過線程ID找到匹配的Chat,若是Chat不存在,那麼它會建立 一個新Chat對象來匹配。要獲得這個新Chat,你必須註冊來獲得通知。能夠註冊一個消息監聽器來接收全部要到來的消息。

//假定已經建立了名爲」connection」的XMPPConnection

ChatManagercm = connection.getChatManager().addChatListener(new ChatManagerListener(){

    @Override

    public void chatCreated(Chat chat, BooleancreatedLocally){

        if(!createdLocally)

            chat.addMessageListener(newMyNewMessageListener());

    }

});

 

除 了基於線程的Chat消息,也有一些客戶端不發送線程ID做爲Chat的一部分。要處理這種狀況,Smack會基於JID嘗試匹配接收的消息到最匹配現有 的Chat。它會嘗試用完整的JID來查找Chat,若是搜不到,再嘗試用基本的JID來查找Chat。若是找不到現有的Chat來匹配,那麼會建立一個 新Chat。

5、名單Roster和在線狀態Presence

名單可讓你跟蹤其餘用戶是否在線,並且名單可讓你把用戶組織到羣組,好比朋友羣或工做羣。而其它的即時通訊IM系統則把名單Roster視爲好友列表、聯繫人列表等等。

 

一、名單條目

名單中的每個用戶都由RosterEntry來表示,它包括:

1)一個XMPP地址(好比」jsmith@example.com」)

2)你爲用戶編寫的備註姓名(好比」Joe」)

3)名單中的羣列表。若是名單的條目不屬於任何羣組,那麼它被稱爲"unfiledentry"。

下面的代碼片斷會打印名單中全部的條目:

Rosterroster = connection.getRoster();

Collection<RosterEntry>entries = roster.getEntries();

for(RosterEntryentry : entries){

    System.out.println(entry);

}

 

還有獲取單個條目的方法、獲取"unfiledentry"的方法,獲取一個羣或全部羣的方法。

 

二、在線狀態

名單中的每一個條目都有一個與之相關的在線狀態。Roster.getPresence(Stringuser)方法會返回一個表示用戶是否在線的Presence對象或者爲空。爲空是你尚未訂閱用戶是否在線的返回。

注意:一般狀況下,在線狀態的訂閱老是綁定到名單中的用戶,但這並不適應全部的狀況。

 

一個用戶的在線狀態要麼是在線,要麼是離線。當用戶在線時,他們的在線狀態還能夠包含擴展的信息,好比用戶當前正在作什麼,用戶是否願意被打擾等等。具體參考Presence類。

 

三、監聽名單Roster和在線狀態Presence的改變

Roster類的典型應用場景是以樹狀結構顯示用戶羣和列表,而且用戶列表中包含用戶是否在線的狀態。好比,參考下圖所示的一個ExodusXMPP客戶端的Roster。

 

在 線狀態的信息可能會常常變化,Roster條目也可能常常修改或刪除。要監聽Roster和Presence數據的變化,你應該使用 RosterListener。要獲得Roster改變的全部提醒,那麼必須在登陸XMPP服務器以前註冊RosterListener。下面的代碼片斷 註冊了一個Roster的RosterListener,它可以在標準輸出中打印任何Presence的改變。一個標準的客戶端可使用相似的代碼用變化 的信息來更新Roster界面。

Rosterroster = con.getRoster();

roster.addRosterListener(newRosterListener(){

    // 忽略事件public void entriesAdded(Collection<String> addresses){}

    public void entriesDeleted(Collection<String>addresses){}

    public voidentriesUpdated(Collection<String> addresses){}

    public void presenceChanged(Presencepresence){

        System.out.println(「Presencechanged: 「+ presence.getFrom() + 「 「 + presence);

    }

});

 

四、添加Entries到Roster

Roster 和Presence使用一種基於權限的模型,用戶必須獲得其餘人的許可才能把這些人添加到Roster。這樣能夠保護用戶的隱私,確保了只有得到贊成的用 戶才能查看到他們的Presence信息。所以,當你想添加某個用戶到你的Roster中,必須獲得該用戶接受你的請求才能夠。

若是有用戶請求訂閱你的在線狀態Presence,這個用戶必須先把你添加到他的Roster,所以他會發起請求,你必須選擇接受或拒絕該請求。Smack經過如下三種方式來處理Presence的預訂請求:

1)自動接受全部Presence的預訂請求

2)自動拒絕全部Presence的預訂請求

3)手動處理每個Presence預訂請求

這 三種方式能夠經過Roster.setSubscriptionMode(intsubscriptionMode)方法來設置請求的處理方式。簡單的客 戶端一般使用第一種自動方式處理預訂請求,而功能比較全的客戶端應該選擇第三種手動處理請求的方式,讓終端用戶自行決定是接受請求或是拒絕請求。若是使用 手動方式,應該註冊一個PacketListener來監聽Presence.Type.SUBSCRIBE類型的Presence包。

相關文章
相關標籤/搜索