XMPP之Smack 介紹

XMPP簡介

原理

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

XMPP協(xié)議網(wǎng)絡(luò)架構(gòu)

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

主要特點

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

工作原理

XMPP服務(wù)器

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

XMPP客戶端

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

XMPP網(wǎng)關(guān)

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

XMPP地址格式

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

XML流

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

XMPP消息格式

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

  • <Message>

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

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

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

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

綁定到TCP

客戶端與服務(wù)器通信的過程中,服務(wù)器必須允許客戶端共享一個TCP連接來傳輸XML節(jié),包括從客戶端傳到服務(wù)器和從服務(wù)器傳到客戶端。
服務(wù)器到服務(wù)器的通信過程中,服務(wù)器必須用一個TCP連接向?qū)Ψ桨l(fā)送XML節(jié),另一個TCP連接(由對方初始化)接受對方的XML節(jié),一共兩個TCP連接。

代碼抽取

建立鏈接

XMPPTCPConnectionConfiguration connectionConfiguration = XMPPTCPConnectionConfiguration.builder()
                .setHost(AppContancts.host)//主機(jī)名
                .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(); 需要手動調(diào)用此方法

登錄

登錄有兩種方式:

  • 在構(gòu)建鏈接的時候去做登錄
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") 調(diào)用此方法就可以在鏈接的時候完成登錄。

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

注冊

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

 // 注冊關(guān)鍵代碼
        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類進(jìn)行模塊管理,本質(zhì)上是用單例模式進(jìn)行實例化,我們可以通過以下代碼進(jìn)行實例化:
 mRoster = Roster.getInstanceFor(mConnection);
        try {
            //設(shè)置對方添加自己好友,需要詢問
            mRoster.setSubscriptionMode(Roster.SubscriptionMode.manual);
            mRoster.reloadAndWait();
        } catch (SmackException.NotLoggedInException e) {
            e.printStackTrace();
        } catch (SmackException.NotConnectedException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 //監(jiān)聽好友狀態(tài)(是否在線)、好友添加、查詢好友結(jié)果等作用        
        mRoster.getEntriesAndAddListener(this, this);
  • RosterListener 顧名思義,這個監(jiān)聽主要針對好友狀態(tài)監(jiān)聽,例如以下分析:
 /**
     * 添加好友的時候,狀態(tài)變化回回調(diào),返回添加好友的XMPP地址集合
     */
    public void entriesAdded(Collection<String> addresses);

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

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

    /**
     * 刪除好友的時候,狀態(tài)變化回調(diào),返回添加好友的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組成,消息內(nèi) 容存儲在body標(biāo)簽里面。

在線消息

  • 獲取聊天管理器
ChatManager mChatManager = ChatManager.getInstanceFor(mConnection);
  • 發(fā)送消息
 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;
    }
  • 消息接收

需要實現(xiàn)兩個回調(diào)監(jiān)聽:ChatManagerListener和ChatMessageListener

ChatManagerListener:

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

ChatMessageListener:

void processMessage(Chat chat, Message message); // 消息接收回調(diào) 
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • XMPP簡介 XMPP協(xié)議簡介 XMPP協(xié)議(Extensible Messaging and PresenceP...
    不規(guī)則先生閱讀 6,372評論 2 31
  • 關(guān)于XMPP最權(quán)威的講解:http://www.jabbercn.org/RFC3920(這個才是最權(quán)威的,下面文...
    隨風(fēng)飄蕩的小逗逼閱讀 1,533評論 1 5
  • 前面關(guān)于即時通訊基礎(chǔ)Socket,大家學(xué)習(xí)使用XMPP之前可以先看看即時通訊系列之Socket簡介 前言 前段時間...
    音符上的碼字員閱讀 4,295評論 3 16
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • 要學(xué)習(xí)基于XMPP協(xié)議的IM開發(fā),首先要熟悉XMPP協(xié)議本身。 XMPP協(xié)議的組成主要的XMPP 協(xié)議范本及當(dāng)今應(yīng)...
    RichieQ閱讀 1,910評論 0 6