一、Smack庫概述
????Smack是一個開源、易用的XMPP/Jabber客戶端庫,它使用Java語言開發(fā),由Jive Software開發(fā)。
????Smack的優(yōu)點是編程簡單。
????Smack的缺點是其API并非為大量并發(fā)用戶設計,每個客戶都要1個線程,占用資源相對較大,因此用Smack做模擬測試時,1臺機器只能模擬有限(數(shù)千個)客戶。
????截止2015年10月25日,Smack庫已經(jīng)發(fā)展到4.1.4版。最新的好消息是Smack在4.1.0版后將直接支持Android系統(tǒng),而無需再使用以前的Smack移植版aSmack庫了。Smack庫源碼托管于GitHub,主頁見: https://github.com/igniterealtime/Smack/
1.1 Smack 4的改變
Smack庫從3.4版發(fā)展到4.0.x版后,其API有較大的變化,主要有:
??1. 把Connection類重命名為XMPPConnection類,XMPPConnection類是XMPPTCPConnection類和XMPPBOSHConnection類的父類。
??2. 把各種Provider類進行了分包
??3. keep-alive(持久連接)機制從smack-core庫移到了smack-extensions庫,keep-alive機制現(xiàn)在由PingManager類提供。
??4. PrivacyList類的toString()方法重命名為getName()
??5. 當Chat實例的所有引用都撤掉后,應該調(diào)用Chat.close()方法
否則Chat對象會有內(nèi)存泄露的隱患,直到ChatManager對象被垃圾回收器回收后內(nèi)存泄露隱患才會消失。
??6. ServerTrustManager類被移除了,如果要使用帶SSL認證的XMPP,你只需提供自己的SSLContext對象給ConnectionConfiguration對象即可。
??7. Packet.setProperty()從smack-core庫移到了smack-extensions庫,其API現(xiàn)在可以在org.jivesoftware.smackx.jiveproperties包中找到。
??8. Connection.getAccountManager()方法現(xiàn)在改成了AccountManager.getInstance(XMPPConnection)方法
??9. 異常API做了改進
??10.ToContains過濾器被移除了
1.2 Smack庫的組成
Smack庫可以內(nèi)嵌到任意的Java應用程序中。Smack庫有數(shù)個JAR文件組成,非常具有靈活性。
??1. smack-core.jar提供了核心XMPP功能。都是XMPP RFC規(guī)范定義的XMPP特性。
??2. smack-extensions.jar支持許多由XMPP Standards Foundation定義的擴展(XEP)功能。包括群聊、文件傳輸、用戶搜索等等。以后可查看文檔《擴展手冊》:https://github.com/igniterealtime/Smack/blob/master/documentation/extensions/index.html(目前還是無效的)
??3. smack-experimental.jar支持許多由XMPP Standards Foundation定義的體驗性(XEP)功能。其API和功能特性都被認為是不穩(wěn)定的。
??4.smack-legacy.jar支持許多由XMPP Standards Foundation定義的遺留(XEP)功能。
??5. smack-bosh.jar支持BOSH通信(XEP-0124規(guī)范定義的)。此代碼被認為處于Beta階段。
??6. smack-jingle.jar支持Jingle。此代碼很老,目前處于無維護的狀態(tài)。
??7. smack-resolver-dnsjava.jar支持對DNS SRV記錄的解析,主要用于那些不支持javax.naming API的平臺。
??8. smack-debug.jar用于協(xié)議流量的增強型GUI調(diào)試器。當調(diào)試模式開啟后,如果它在類路徑下,它會自動被使用。以后可查看文檔《調(diào)試模式》:https://github.com/igniterealtime/Smack/blob/master/documentation/debugging.html(目前還是無效的)
二、Smack的配置
Smack的初始化過程涉及到2階段的調(diào)用。
??1.初始化系統(tǒng)屬性通過SmackConfiguration類初始化所有的系統(tǒng)可訪問屬性,這些屬性都是通過getXXX方法取回屬性值的。
??2. 初始化啟動類如果繼承了SmackInitializer接口后,都可以在調(diào)用initialize()方法后得到初始化,這意味著得到初始化的類在啟動后都是活動的。如果沒有繼承SmackInitializer接口,那么要實現(xiàn)初始化,必須要放置一個靜態(tài)代碼塊來實現(xiàn)——他在類裝載時會自動執(zhí)行。初始化是通過配置文件來完成的。默認情況下,Smack會載入Smack JAR文件中內(nèi)嵌的配置文件(它位于org.jivesoftware.smack/smack-config.xml)。這個指定的配置文件包含了一系列需載入初始化的類列表。所有的管理器類型的類都需要被初始化,這些管理器類就包含在上面所說的初始化列表中。
三、XMPPConnection管理
3.1 創(chuàng)建連接
org.jivesoftware.smack.XMPPConnection類可管理到XMPP服務器的連接,它默認的連接實現(xiàn)類是org.jivesoftware.smack.XMPPTCPConnection。它主要使用兩個構(gòu)造方法,
??一個是XMPPTCPConnection(StringserverName)方法,參數(shù)為服務器名。連接會使用所有默認的設置,有:
????1)執(zhí)行DNSSRV查詢,找到服務器確切的地址和端口(通常是5222)。
????2)與服務器協(xié)商最大數(shù)安全,包括TLS加密。但如果有必要,連接會回落到較低的安全設置。
????3)XMPP資源名“Smack”會被用于連接。
??第二個是XMPPTCPConnection(ConnectionConfigurationcc)構(gòu)造器,它會指定高級的連接設置。其中包括:
????1)手動指定服務器地址和端口,而不是通過DNSSRV查詢。
????2)能開啟連接壓縮。
????3)指定自定義的連接資源名(如Work或Home)。用戶到服務器的每一個連接都必須有唯一的資源名。比如對于用戶"jsmith@example.com",完整的帶資源的地址應該是"jsmith@example.com/Smack"。通過攜帶唯一的資源名,用戶可以同時從不同的位置登錄到同一個服務器,這適用于多設備的情況。每一個資源使用的在線優(yōu)先級值:用于決定由哪一個帶資源的指定連接來接收到地址"jsmith@example.com"的消息。
第一種連接方式:
boolean target = false;
AbstractXMPPConnection conn = new XMPPTCPConnection(username, password, serverName);
try {
conn.connect();
target = conn.isConnected();
if(target){
System.out.println("XMPP 服務器連接成功");
}else{
System.out.println("XMPP 服務器連接不成功");
}
} catch (SmackException | IOException | XMPPException e) {
e.printStackTrace();
}
第二種連接方式:
boolean target=false;
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword(username, password)
.setServiceName(serverName)
.setHost(serverName)
.setPort(5222)
.build();
AbstractXMPPConnection conn = new XMPPTCPConnection(config);
try {
conn.connect();
target = conn.isConnected();
if(target){
System.out.println("XMPP 服務器連接成功");
}else{
System.out.println("XMPP 服務器連接不成功");
}
} catch (SmackException | IOException | XMPPException e) {
e.printStackTrace();
}
3.2 連接和關閉連接
//為新連接創(chuàng)建配置
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()方法,它會嘗試建立一個新連接。如果手動嘗試也失敗了,那么重連管理器會繼續(xù)重連的工作。
四、使用Chat消息通信
????來回收發(fā)消息是即時通信的核心功能。盡管單條消息是以包的形式發(fā)送和接收的,通常還是把他視為聊天的消息字符串,使用org.jivesoftware.smack.Chat類。
4.1 Chat類
????一個聊天Chat會在兩個用戶之間創(chuàng)建一個消息線程(通過線程ID)。下面的代碼片段演示了怎樣創(chuàng)建一個新聊天,然后向用戶發(fā)送一條文本消息:
//假設已經(jīng)創(chuàng)建了一個名為"connection"的XMPPConnection
ChatManager chatmanager = connection.getChatManager();
Chat newChat = 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)方法可以方便地創(chuàng)建一個消息Message對象,用字符串參數(shù)設置消息正文Body,然后發(fā)送消息。在某些情況下你可能希望在發(fā)送消息前設置額外的值,使用Chat.createMessage()方法和Chat.sendMessage(Message)方法,如下面的代碼片段所示:
Message newMessage = new Message();
newMessage.setBody(“Howdy!”);
message.setProperty(“favoriteColor”,“red”);
newChat.sendMessage(newMessage);
前面的例子中,我們可以注意到,在創(chuàng)建聊天Chat時指定了一個消息監(jiān)聽器MessageListener,在任意時刻,當來自其它用戶的聊天消息到達后,消息監(jiān)聽器會得到通知。下面的代碼片段使用了監(jiān)聽器做鸚鵡學舌,它會回顯來自其他用戶傳遞的消息。
//假設在聊天Chat中已經(jīng)設置了消息監(jiān)聽器MessageListener
publicvoid processMessage(Chat chat, Message message){
// 把用戶發(fā)送的消息內(nèi)容發(fā)送給用戶
chat.sendMessage(message.getBody());
}
4.2 來電聊天
????當提示有另一個用戶的聊天消息到了后,設置有輕微的不同,因為你是首次接收到聊天消息。取代明確地創(chuàng)建一個Chat來發(fā)送消息,當ChatManager創(chuàng)建了Chat實例后,你需要注冊處理新創(chuàng)建的Chat實例。ChatManager會通過線程ID找到匹配的Chat,如果Chat不存在,那么它會創(chuàng)建一個新Chat對象來匹配。要得到這個新Chat,你必須注冊來得到通知。可以注冊一個消息監(jiān)聽器來接收所有要到來的消息。
//假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
ChatManager cm = connection.getChatManager().addChatListener(
new ChatManagerListener(){
@Override
public void chatCreated(Chat chat, BooleancreatedLocally){
if(!createdLocally)
chat.addMessageListener(newMyNewMessageListener());
}
});
????除了基于線程的Chat消息,也有一些客戶端不發(fā)送線程ID作為Chat的一部分。要處理這種情況,Smack會基于JID嘗試匹配接收的消息到最匹配現(xiàn)有的Chat。它會嘗試用完整的JID來查找Chat,如果搜不到,再嘗試用基本的JID來查找Chat。如果找不到現(xiàn)有的Chat來匹配,那么會創(chuàng)建一個新Chat。
五、名單Roster和在線狀態(tài)Presence
名單可以讓你跟蹤其他用戶是否在線,而且名單可以讓你把用戶組織到群組,比如朋友群或工作群。而其它的即時通信IM系統(tǒng)則把名單Roster視為好友列表、聯(lián)系人列表等等。
5.1 名單條目
????Roster用于跟蹤其他用戶是否在線。用戶的聯(lián)系人可以以分組的方式進行組織,比如“好友”、“同事”。然后就可以查看組中的每個用戶是否在線了。要檢索Roster,使用XMPPConnection.getRoster()方法。Roster類允許你查找所有的Roster實體,以及他們屬于哪個組,每個實體當前的在線狀態(tài)。名單中的每一個用戶都由RosterEntry來表示,它包括:
????1)一個XMPP地址(比如”jsmith@example.com”)
????2)你為用戶編寫的備注姓名(比如”Joe”)
????3)名單中的群列表。如果名單的條目不屬于任何群組,那么它被稱為"unfiledentry"。
下面的代碼片段會打印名單中所有的條目:
//假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
Rosterroster = connection.getRoster();
Collection<RosterEntry>entries = roster.getEntries();
for(RosterEntryentry : entries){
System.out.println(entry);
}
還有獲取單個條目的方法、獲取"unfiledentry"的方法,獲取一個群或所有群的方法。
5.2 在線狀態(tài)
????名單中的每個條目都有一個與之相關的在線狀態(tài)。Roster.getPresence(Stringuser)方法會返回一個表示用戶是否在線的Presence對象。如果為空是你還沒有訂閱用戶是否在線的返回。注意:通常情況下,在線狀態(tài)的訂閱總是綁定到名單中的用戶,但這并不適應所有的情況。
????一個用戶的在線狀態(tài)要么是在線,要么是離線。當用戶在線時,他們的在線狀態(tài)還可以包含擴展的信息,比如用戶當前正在做什么,用戶是否愿意被打擾等等。具體參考Presence類。
5.3 監(jiān)聽名單Roster和在線狀態(tài)Presence的改變
????Roster類的典型應用場景是以樹狀結(jié)構(gòu)顯示用戶群和列表,并且用戶列表中包含用戶是否在線的狀態(tài)。比如,參考下圖所示的一個ExodusXMPP客戶端的Roster。
????在線狀態(tài)的信息可能會經(jīng)常變化,Roster條目也可能經(jīng)常修改或刪除。要監(jiān)聽Roster和Presence數(shù)據(jù)的變化,你應該使用RosterListener。要得到Roster改變的所有提醒,那么必須在登錄XMPP服務器之前注冊RosterListener。下面的代碼片段注冊了一個Roster的RosterListener,它能夠在標準輸出中打印任何Presence的改變。一個標準的客戶端可以使用類似的代碼用變化的信息來更新Roster界面。
//假定已經(jīng)創(chuàng)建了名為”connection”的XMPPConnection
Roster roster = connection.getRoster();
roster.addRosterListener(new RosterListener(){
// 忽略事件
public void entriesAdded(Collection<String> addresses){}
public void entriesDeleted(Collection<String>addresses){}
public void entriesUpdated(Collection<String> addresses){}
public void presenceChanged(Presencepresence){
System.out.println(“Presencechanged: “+ presence.getFrom() + “ “ + presence);
}
});
5.4 添加Entries到Roster
????Roster和Presence使用一種基于權限的模型,用戶必須得到其他人的許可才能把這些人添加到Roster。這樣可以保護用戶的隱私,確保了只有獲得同意的用戶才能查看到他們的Presence信息。因此,當你想添加某個用戶到你的Roster中,必須得到該用戶接受你的請求才可以。
如果有用戶請求訂閱你的在線狀態(tài)Presence,這個用戶必須先把你添加到他的Roster,因此他會發(fā)起請求,你必須選擇接受或拒絕該請求。Smack通過以下三種方式來處理Presence的預訂請求:
????1)自動接受所有Presence的預訂請求
????2)自動拒絕所有Presence的預訂請求
????3)手動處理每一個Presence預訂請求
????這三種方式可以通過Roster.setSubscriptionMode(intsubscriptionMode)方法來設置請求的處理方式。簡單的客戶端通常使用第一種自動方式處理預訂請求,而功能比較全的客戶端應該選擇第三種手動處理請求的方式,讓終端用戶自行決定是接受請求或是拒絕請求。如果使用手動方式,應該注冊一個PacketListener來監(jiān)聽Presence.Type.SUBSCRIBE類型的Presence包。
六、讀寫Packet(數(shù)據(jù)包)
????從客戶端發(fā)送到XMPP服務器的每一條消息都稱為一個Packet(數(shù)據(jù)包)。org.jivesoftware.smack.packet庫中包含了XMPP支持的消息Message、在線狀態(tài)Presence、IQ)三種不同的基本數(shù)據(jù)包類型的封裝類。而像Chat或GroupChat這樣的類則提供了更高層的結(jié)構(gòu)來管理數(shù)據(jù)包的自動創(chuàng)建和發(fā)送。但是,開發(fā)者還是可以直接創(chuàng)建和發(fā)送數(shù)據(jù)包的。下面的代碼就是修改自己的在線狀態(tài),讓其他人知道你不在線。
//假設已經(jīng)創(chuàng)建了一個名為"connection"的XMPPConnection
Presence presence = new Presence(Presence.Type.unavailable);
presence.setStatus("Gone fishing");
connection.sendStanza(presence);
6.1 PacketListener與PacketCollector
Smack提供了兩種讀取到來的數(shù)據(jù)包的方式:
????org.jivesoftware.smack.PacketCollector(包收集器):該類提供synchronously(同步)方法,等待接受數(shù)據(jù)包(Packets).
????org.jivesoftware.smack.PacketListener(包監(jiān)聽器): 該接口提供asynchronously(異步)方法,等待結(jié)束數(shù)據(jù)(Packets)。
????兩者都使用PacketFilter實例來判斷應該處理哪一個數(shù)據(jù)包。PacketListener(包監(jiān)聽器)用于事件風格的編程,而PacketCollector(包收集器)有一個數(shù)據(jù)包的結(jié)果隊列,你可以做輪詢或阻塞等操作。也就是說,如果你想在數(shù)據(jù)包到來時執(zhí)行一些動作,那么包監(jiān)聽器很適合。如果你想等待指定的數(shù)據(jù)包的到來,那么包收集器很適合。包收集器和包監(jiān)聽器都使用Connection連接實例創(chuàng)建。
????數(shù)據(jù)包集合(PacketCollector)和數(shù)據(jù)包接口(PacketListener)是通過XMPPConnection實例對象創(chuàng)建。
6.2 攔截器
????org.jivesoftware.smack.filter.StanzaFilter接口可以決定,那些特定的數(shù)據(jù)包會被傳遞到PacketCollector 或者PacketListener。
許多預先定義的攔截器都實現(xiàn)了org.jivesoftware.smack.filter接口。
下面的代碼片段,演示了注冊的數(shù)據(jù)包監(jiān)聽器和數(shù)據(jù)包集合
// Create a packet filter to listen for new messages from a particular
// user. We use an AndFilter to combine two other filters._
StanzaFilter filter = new AndFilter(new StanzaTypeFilter(Message.class),
new FromContainsFilter("mary@jivesoftware.com"));
// Assume we've created an XMPPConnection name "connection".
// First, register a packet collector using the filter we created.
PacketCollector myCollector = connection.createPacketCollector(filter);
// Normally, you'd do something with the collector, like wait for new packets.
// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {
**public** **void** processPacket(Packet packet) {
// Do something with the incoming packet here._
}
};
// Register the listener._
connection.addPacketListener(myListener, filter);
標準段落(字符)攔截器
????smack 類庫中已經(jīng)包含很多包攔截器,你也可以創(chuàng)建屬于自己的攔截器,只需要代碼實現(xiàn)StanzaFilter接口,默認的攔截器包含如下:
- StanzaTypeFilter --特定類型的數(shù)據(jù)包過濾器
- StanzaIdFilter -- 特定數(shù)據(jù)包標識篩選器
- ThreadFilter -- 特定線程標識數(shù)據(jù)包過濾器
- ToContainsFilter -- 特定發(fā)送地址數(shù)據(jù)包過濾器
- FromContainsFilter -- 特定接受地址數(shù)據(jù)包過濾器.
- StanzaExtensionFilter -- 特定包擴展數(shù)據(jù)包過濾器
- AndFilter -- implements the logical AND operation over two filters.
- OrFilter -- implements the logical OR operation over two filters.
- NotFilter -- implements the logical NOT operation on a filter.
七、信息包插件提供者
????Smack提供的體系是堵塞自定義的XML信息包擴展和IQ包分析器的系統(tǒng)(The Smack provider architecture is a system for plugging in custom XML parsing of packet extensions and IQ packets)。標準的Smack擴展(Smack Extensions)是使用提供者的體系結(jié)構(gòu)搭建的。存在以下兩種類型的提供者:
- IQProvider –將IQ請求( IQ requests)解析成Java對象(Java objects)
- PacketExtension – 將附屬在信息包上的XML子文檔解析成信息包擴展實例(PacketExtension instances)
7.1 IQProvider
???? IQProvider 默認情況下,Smack只知道如何處理類似以下幾個名字空間的子信息包的IQ信息包(IQ packets):
???? jabber:iq:auth
???? jabber:iq:roster
???? jabber:iq:register
因為許多IQ類型是XMPP及其擴展部分的一部分,所以提供一個可插入的IQ分析機制。IQ Providers被程序自動的注冊或通過創(chuàng)建在你的JAR 文件的META-INF目錄下創(chuàng)建一個mack.providers文件。該文件是一個包含一個或多個iqProvider條目(iqProvider entries)的XML文檔,如下例所示:
<?xml version="1.0"?>
<smackProviders>
<iqProvider>
<elementName>query</elementName>
<namespace>jabber:iq:time</namespace>
<className>org.jivesoftware.smack.packet.Time</className>
</iqProvider>
</smackProviders>
????每一個IQ provider都和一個元素名(element name)和名字空間( namespace)相聯(lián)系。在上面的例子中,元素名是query,名字空間是abber:iq:time。如果有多重提供者條目(multiple provider entries)嘗試注冊并控制相同的名字空間,那么從類路徑(classpath)載入的第一個條目將有優(yōu)先權。
????IQ provider類可以實現(xiàn)IQProvide接口,或者繼承IQ類。在前面的例子中,每一個IQProvider負責解析原始的XML流從而創(chuàng)建一個IQ實例。在下面的例子中,bean introspection將被用于嘗試自動使用在IQ packet XML中發(fā)現(xiàn)的值設置IQ實例的屬性。一個XMPP時間信息包如下所示:
<iq type=’result’ to=’joe@example.com’ from=’mary@example.com’ id=’time_1’>
<query xmlns=’jabber:iq:time’>
<utc>20020910T17:58:35</utc>
<tz>MDT</tz>
<display>Tue Sep 10 12:58:35 2002</display>
</query>
</iq>
????為了讓這個信息包自動的映射成上面的providers file中所列的時間對象(Time object),它必須有以下幾個方法:setUtc(String), setTz(String), 和 setDisplay(String)。自動檢查(introspection)的服務將試著自動的將字符串值轉(zhuǎn)化成a boolean, int, long, float, double,或 Class 類型。轉(zhuǎn)化成何種類型由IQ實例的需要來決定。
7.2 PacketExtensionProvider
????PacketExtensionProvider 信息包插件提供者(Packet extension providers)為信息包提供一個可插入的系統(tǒng),這些信息包是一個IQ, message和presence packets的自定義名字空間的子元素。每一個插件提供者(extension provider)使用一個元素名(element name)和名字空間(namespace)在smack.providers文件中注冊,如下例所示:
<?xml version="1.0"?>
<smackProviders>
<extensionProvider>
<elementName>x</elementName>
<namespace>jabber:iq:event</namespace>
<className>org.jivesoftware.smack.packet.MessageEvent</className>
</extensionProvider>
</smackProviders>
????如果有多重提供者條目(multiple provider entries)嘗試注冊并控制相同的名字空間,那么從類路徑(classpath)載入的第一個條目將有優(yōu)先權。 一旦在一個信息包中發(fā)現(xiàn)信息包插件,解析器將傳遞到正確的提供者。每一個提供者可以實現(xiàn)PacketExtensionProvider接口或者是一個標準的Java Bean。在前面的例子中,每一個插件提供者(extension provider)負責解析原始的XML流去構(gòu)造一個實例。在下面的例子中,bean introspection將被用于嘗試自動使用在信息包插件子元素(packet extension sub-element)中的值設置類的屬性。 當一個插件提供者(extension provider)沒有用元素名(element name)和名字空間(namespace)對注冊是,Smack將存儲所有在缺省信息包插件(DefaultPacketExtension)對象中的最高級別元素(top-level elements),并匹配到信息包上。
七、smack debug模式講解
????smakc 內(nèi)置兩套debuging 控制臺,讓你追蹤XMPP服務端和客戶端之間所有XML 流動,在smack-debug.jar包含Lite調(diào)試器和增強調(diào)試器,在smack-core.jar包含debug輸出控制臺。
調(diào)試模式可以用不同的方式來啟用:
1、在創(chuàng)建新連接之前,先添加以下代碼行:
SmackConfiguration.DEBUG = true;
1、設置Java系統(tǒng)屬性smack.debugenabled真實。可以在命令行上設置系統(tǒng)屬性,例如:
java -Dsmack.debugEnabled=true SomeApp
如果你希望在你的應用程序中顯式禁用調(diào)試模式,可以通過使用命令行參數(shù) 或者是在在打開新連接之前,請在應用程序中添加以下行:
SmackConfiguration.DEBUG = false;
smack 使用以下邏輯決定調(diào)試控制臺使用;
1、它首先會嘗試使用在Java系統(tǒng)屬性指定類smack.debuggerclass調(diào)試器。如果你需要開發(fā)屬于自己的Debug,需要smackdebugger接口,然后設置系統(tǒng)屬性的命令行如:
java -Dsmack.debuggerClass=my.company.com.MyDebugger SomeApp
2、如果第一步失敗,Smack會嘗試使用增強型Debug,smackx-debug.jar文件中包含了增強型Debug,因此,你需要將jar文件的路徑添加到ClassPath路徑中。smack-core.jar Lite調(diào)試器和增強調(diào)試器不可用的情況下,只有控制臺調(diào)試器。
增強調(diào)試器
????當smack Debug模式是啟動時,Debug窗口會顯示每一個創(chuàng)建連接信息,同時也包含以下信息:
- XMPPConnection tabs -- 每個選項卡顯示有關連接的調(diào)試信息.
- Smack info tab -- shows information about Smack (e.g. Smack version, installed components, etc.). The connection tab will contain the following information:
- All Stanzas --通過smack 分析發(fā)送和接收的數(shù)據(jù)包的信息分析.
- Raw Sent Stanzas -- 通過Smack產(chǎn)生的原始XML流量發(fā)送到服務器.
- Raw Received Stanzas -- 服務器向客戶端發(fā)送的原始XML.
- Ad-hoc message -- 允許發(fā)送特定類型的數(shù)據(jù)包.
- Information -- 顯示連接狀態(tài)和統(tǒng)計數(shù).
Lite Debugger
????當smack Debug模式是啟動時,Debug窗口會顯示每一個創(chuàng)建連接信息,同時也包含以下信息:
- Client Traffic (red text) -- 通過Smack產(chǎn)生的原始XML流量發(fā)送到服務器.
- Server Traffic (blue text) --服務器向客戶端發(fā)送的原始XML.
- Interpreted Stanzas (green text) -- shows XML packets from the server as parsed by Smack. Right click on any of the panes to bring up a menu with the choices to copy of the contents to the system clipboard or to clear the contents of the pane.