XMPP之Smack 介紹

XMPP簡介

原理

  • 概述
    XMPP(可擴展消息處理現場協議)是基于可擴展標記語言(XML)的協議,它用于即時消息(IM)以及在線現場探測。它在促進服務器之間的準即時操作。這個協議可能最終允許因特網用戶向因特網上的其他任何人發送即時消息,即使其操作系統和瀏覽器不同。
工作原理圖

XMPP協議網絡架構

XMPP是一個典型的C/S架構,而不是像大多數即時通訊軟件一樣,使用P2P客戶端到客戶端的架構,也就是說在大多數情況下,當兩個客戶端進行通訊時,他們的消息都是通過服務器傳遞的(也有例外,例如在兩個客戶端傳輸文件時).采用這種架構,主要是為了簡化客戶端,將大多數工作放在服務器端進行,這樣,客戶端的工作就比較簡單,而且,當增加功能時,多數是在服務器端進行.XMPP服務的框架結構如下圖所示.XMPP中定義了三個角色,XMPP客戶端,XMPP服務器、網關.通信能夠在這三者的任意兩個之間雙向發生.服務器同時承擔了客戶端信息記錄、連接管理和信息的路由功能.網關承擔著與異構即時通信系統的互聯互通,異構系統可以包括SMS(短信)、MSN、ICQ等.基本的網絡形式是單客戶端通過TCP/IP連接到單服務器,然后在之上傳輸XML

主要特點

  • XMPP 協議是公開的,由JSF開源社區組織開發的。XMPP 協議并不屬于任何的機構和個人,而是屬于整個社區,這一點從根本上保證了其開放性。
  • XMPP 協議具有良好的擴展性。在XMPP 中,即時消息和到場信息都是基于XML 的結構化信息,這些信息以XML 節(XML Stanza)的形式在通信實體間交換。XMPP 發揮了XML 結構化數據的通用傳輸層的作用,它將出席和上下文敏感信息嵌入到XML 結構化數據中,從而使數據以極高的效率傳送給最合適的資源。基于XML 建立起來的應用具有良好的語義完整性和擴展性。
  • 分布式的網絡架構。XMPP 協議都是基于Client/Server 架構,但是XMPP協議本身并沒有這樣的限制。網絡的架構和電子郵件十分相似,但沒有結合任何特定的網絡架構,適用范圍非常廣泛。
  • XMPP 具有很好的彈性。XMPP 除了可用在即時通信的應用程序,還能用在網絡管理、內容供稿、協同工具、檔案共享、游戲、遠端系統監控等。
  • 安全性。XMPP在Client-to-Server通信,和Server-to-Server通信中都使用TLS (Transport Layer Security)協議作為通信通道的加密方法,保證通信的安全。任何XMPP服務器可以獨立于公眾XMPP網絡(例如在企業內部網絡中),而使用SASL及TLS等技術更加增強了通信的安全性。如下圖所示:

工作原理

XMPP服務器

XMPP 服務器遵循兩個主要法則:
(1)監聽客戶端連接,并直接與客戶端應用程序通信;
(2)與其他 XMPP 服務器通信;
XMPP開源服務器一般被設計成模塊化,由各個不同的代碼包構成,這些代碼包分別處理Session管理、用戶和服務器之間的通信、服務器之間的通信、DNS(Domain Name System)轉換、存儲用戶的個人信息和朋友名單、保留用戶在下線時收到的信息、用戶注冊、用戶的身份和權限認證、根據用戶的要求過濾信息和系統記錄等。另外,服務器可以通過附加服務來進行擴展,如完整的安全策略,允許服務器組件的連接或客戶端選擇,通向其他消息系統的網關。
基本的XMPP 服務器必須實現以下標準協議:
RFC3920 核心協議Core
RFC3921 即時消息和出席協議Instant Messaging and Presence
XEP-0030 服務發現Service Discovery

XMPP客戶端

XMPP 系統的一個設計標準是必須支持簡單的客戶端。事實上,XMPP 系統架構對客戶端只有很少的幾個限制。一個XMPP 客戶端必須支持的功能有:
(1)通過 TCP 套接字與XMPP 服務器進行通信;
(2)解析組織好的 XML 信息包;
(3)理解消息數據類型。
XMPP 將復雜性從客戶端轉移到服務器端。這使得客戶端編寫變得非常容易,更新系統功能也同樣變得容易。XMPP 客戶端與服務端通過XML 在TCP 套接字的5222 端口進行通信,而不需要客戶端之間直接進行通信。
基本的XMPP 客戶端必須實現以下標準協議(XEP-0211):
RFC3920 核心協議Core
RFC3921 即時消息和出席協議Instant Messaging and Presence
XEP-0030 服務發現Service Discovery
XEP-0115 實體能力Entity Capabilities

XMPP網關

XMPP 突出的特點是可以和其他即時通信系統交換信息和用戶在線狀況。由于協議不同,XMPP 和其他系統交換信息必須通過協議的轉換來實現,目前幾種主流即時通信協議都沒有公開,所以XMPP 服務器本身并沒有實現和其他協議的轉換,但它的架構允許轉換的實現。實現這個特殊功能的服務端在XMPP 架構里叫做網關(gateway)。目前,XMPP 實現了和AIM、ICQ、IRC、MSN Massager、RSS0.9 和Yahoo Massager 的協議轉換。由于網關的存在,XMPP 架構事實上兼容所有其他即時通信網絡,這無疑大大提高了XMPP 的靈活性和可擴展性。

XMPP地址格式

一個實體在XMPP網絡結構中被稱為一個接點,它有唯一的標示符jabber identifier(JID),即實體地址,用來表示一個Jabber用戶,但是也可以表示其他內容,例如一個聊天室.一個有效的JID包括一系列元素:(1)域名(domain identifier);(2)節點(node identifier);(3)源(resource identifier).它的格式是node@domain/resource,node@domain,類似電子郵件的地址格式.domain用來表示接點不同的設備或位置,這個是可選的,例如a在Server1上注冊了一個用戶,用戶名為doom,那么a的JID就是doom@serverl,在發送消息時,指明doom@serverl就可以了,resource可以不用指定,但a在登錄到這個Server時,fl的JID可能是doom@serverl、exodus(如果a用Exodus軟件登錄),也可能是doom@serverl/psi(如果a用psi軟件登錄).資源只用來識別屬于用戶的位置或設備等,一個用戶可以同時以多種資源與同一個XMPP服務器連接。

XML流

MPP本質上是一種XML流技術。客戶端開始和XMPP服務器會話,會打開一個長時間的TCP連接,然后和服務器協商一個流。一旦你和你的服務器建立了一個XML流,你和你的服務器可以通過流交換三個特殊的XML片段:<message/>,<presence/>,<iq/>.這些片段稱為XML節。是XML中最有意義的基本單元,而且一旦你已建立一個XML流,你可以通過流發送無數個節。

XMPP消息格式

XMPP中定義了3個頂層XML元素: Message、Presence、IQ,下面針對這三種元素進行介紹。

  • <Message>

用于在兩個jabber用戶之間發送信息。Jsm(jabber會話管理器)負責滿足所有的消息,不管目標用戶的狀態如何。如果用戶在線jsm立即提交;否則jsm就存儲。
To :標識消息的接收方。
from : 指發送方的名字或標示(id)o
Text: 此元素包含了要提交給目標用戶的信息。
結構如下所示:

     <message to= ‘lily@jabber.org/contact’ type =’chat’>
        <body> 你好,在忙嗎 </body>
        </message> 
  • <Presence>
    用來表明用戶的狀態,如:online、away、dnd(請勿打擾)等。當用戶離線或改變自己的狀態時,就會在stream的上下文中插入一個Presence元素,來表明自身的狀態.結構如下所示:
<presence>
        From =‘lily @ jabber.com/contact’
        To = ‘yaoman @ jabber.com/contact'
    <status>Online</status>
    </presence>

presence元素可以取下面幾種值:
Probe :用于向接受消息方法發送特殊的請求
subscribe:當接受方狀態改變時,自動向發送方發送presence信息。

  • <IQ>
    一種請求/響應機制,從一個實體從發送請求,另外一個實體接受請求,并進行響應.例如,client在stream的上下文中插入一個元素,向Server請求得到自己的好友列表,Server返回一個,里面是請求的結果.
    其主要屬性是type,包括:
    主要的屬性是type。包括:
    Get :獲取當前域值。
    Set :設置或替換get查詢的值。
    Result :說明成功的響應了先前的查詢。
    Error: 查詢和響應中出現的錯誤。
    結構如下所示:
<iq from =‘lily @ jabber.com/contact’id=’1364564666’ Type=’result’>

綁定到TCP

客戶端與服務器通信的過程中,服務器必須允許客戶端共享一個TCP連接來傳輸XML節,包括從客戶端傳到服務器和從服務器傳到客戶端。
服務器到服務器的通信過程中,服務器必須用一個TCP連接向對方發送XML節,另一個TCP連接(由對方初始化)接受對方的XML節,一共兩個TCP連接。

代碼抽取

建立鏈接

XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
                .setHost(AppContancts.host)//主機名
                .setPort(AppContancts.port)//端口
                .setServiceName(AppContancts.host)
                .setSendPresence(true)// support presence
                .setConnectTimeout(1000 * 10)
                .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)//越過證書
                .build();

mConnection = new XMPPTCPConnection(connectionConfiguration);
mConnection.connect();      

mConnection.connect(); 需要手動調用此方法

登錄

登錄有兩種方式:

  • 在構建鏈接的時候去做登錄
XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
                .setHost(AppContancts.host)
                .setPort(AppContancts.port)
                .setServiceName(AppContancts.host)
                .setSendPresence(true)// support presence
                .setConnectTimeout(1000 * 10)
                .setUsernameAndPassword("Leo","123")
                .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)//越過證書
                .build();

        mConnection = new XMPPTCPConnection(connectionConfiguration);

setUsernameAndPassword("Leo","123") 調用此方法就可以在鏈接的時候完成登錄。

  • 完成構建后手動調用login()方法
     if (mConnection.isConnected()){
                mConnection.login("Leo","123");
            }

注冊

注冊時,需要先連接成功才能完成注冊

 // 注冊關鍵代碼
        AccountManager accountManager = AccountManager.getInstance(mConnection);
        try {
            accountManager.createAccount("lexiaowen", "123");
        } catch (XMPPException e) {
            e.printStackTrace();
        } catch (SmackException.NotConnectedException e) {
            e.printStackTrace();
        } catch (SmackException.NoResponseException e) {
            e.printStackTrace();
        }

好友管理

  • 首先好友管理由 org.jivesoftware.smack.roster.Roster類進行模塊管理,本質上是用單例模式進行實例化,我們可以通過以下代碼進行實例化:
 mRoster = Roster.getInstanceFor(mConnection);
        try {
            //設置對方添加自己好友,需要詢問
            mRoster.setSubscriptionMode(Roster.SubscriptionMode.manual);
            mRoster.reloadAndWait();
        } catch (SmackException.NotLoggedInException e) {
            e.printStackTrace();
        } catch (SmackException.NotConnectedException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 //監聽好友狀態(是否在線)、好友添加、查詢好友結果等作用        
        mRoster.getEntriesAndAddListener(this, this);
  • RosterListener 顧名思義,這個監聽主要針對好友狀態監聽,例如以下分析:
 /**
     * 添加好友的時候,狀態變化回回調,返回添加好友的XMPP地址集合
     */
    public void entriesAdded(Collection<String> addresses);

    /**
     * 添加好友的時候,狀態變化回回調,返回添加好友的XMPP地址集合
     */
    public void entriesUpdated(Collection<String> addresses);

    /**
     * 好友信息更新的時候回調,返回添加好友的XMPP地址集合。一般可以利用更新本地數據庫
     */
    public void entriesDeleted(Collection<String> addresses);

    /**
     * 刪除好友的時候,狀態變化回調,返回添加好友的XMPP地址集合
     */
    public void presenceChanged(Presence presence);
  • 添加好友
private void addRosyer(String user, String name, String[] groupName) {
        if (mConnection.isAuthenticated()) {
            try {
                mRoster.createEntry(user, name, groupName);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • 刪除好友
  //刪除好友
    public void deleteRoster(String user) {
        RosterEntry entry = mRoster.getEntry(user);
        if (entry != null) {
            try {
                mRoster.removeEntry(entry);
            } catch (SmackException.NotLoggedInException |
                    SmackException.NoResponseException |
                    XMPPException.XMPPErrorException |
                    SmackException.NotConnectedException e) {
                e.printStackTrace();
            }
        }
    }
  • 添加分組
 //添加分組
    public void addGroup(String groupName) {
        mRoster.createGroup(groupName);
    }

消息管理

Smack中的基本消息由org.jivesoftware.smack.packet.Message組成,消息內 容存儲在body標簽里面。

在線消息

  • 獲取聊天管理器
ChatManager mChatManager = ChatManager.getInstanceFor(mConnection);
  • 發送消息
 Message message = new Message();
                        message.setBody("hello f123");
                        sendMessage(createChat("f123@192.168.99.212"), message);
  public Chat createChat(String userJid) {
        ChatManager mChatManager = ChatManager.getInstanceFor(mConnection);
        Chat curChat = null;
        curChat = mChatManager.createChat(userJid);
        curChat.addMessageListener(this);
        return curChat;
    }
  • 消息接收

需要實現兩個回調監聽:ChatManagerListener和ChatMessageListener

ChatManagerListener:

void chatCreated(Chat chat, boolean createdLocally); // 聊天會話被創建回調

ChatMessageListener:

void processMessage(Chat chat, Message message); // 消息接收回調 
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容

  • XMPP簡介 XMPP協議簡介 XMPP協議(Extensible Messaging and PresenceP...
    不規則先生閱讀 6,341評論 2 31
  • 關于XMPP最權威的講解:http://www.jabbercn.org/RFC3920(這個才是最權威的,下面文...
    隨風飄蕩的小逗逼閱讀 1,518評論 1 5
  • 前面關于即時通訊基礎Socket,大家學習使用XMPP之前可以先看看即時通訊系列之Socket簡介 前言 前段時間...
    音符上的碼字員閱讀 4,266評論 3 16
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,816評論 18 139
  • 要學習基于XMPP協議的IM開發,首先要熟悉XMPP協議本身。 XMPP協議的組成主要的XMPP 協議范本及當今應...
    RichieQ閱讀 1,899評論 0 6