關(guān)于XMPP最權(quán)威的講解:http://www.jabbercn.org/RFC3920(這個(gè)才是最權(quán)威的,下面文章只是博客中)
什么是OpenFire
Openfire 采用Java開發(fā),開源的實(shí)時(shí)協(xié)作(RTC)服務(wù)器基于XMPP(Jabber)協(xié)議。
您可以使用它輕易的構(gòu)建高效率的即時(shí)通信服務(wù)器。Openfire安裝和使用都非常簡單,并利用Web進(jìn)行管理其障。單臺(tái)服務(wù)器可支持上萬并發(fā)用戶。
由于是采用開放的XMPP協(xié)議涂佃,您可以使用各種支持XMPP協(xié)議的IM客戶端軟件登陸服務(wù)励翼。
XMPP(Jabber)協(xié)議
1、 介紹
XMPP是一種基于XML的協(xié)議辜荠,它繼承了在XML環(huán)境中靈活的擴(kuò)展性汽抚。因此,基于XMPP的應(yīng)用具有超強(qiáng)的可擴(kuò)展性侨拦。經(jīng)過擴(kuò)展以后的XMPP可以通過發(fā) 送擴(kuò)展的信息來處理用戶的需求,以及在XMPP的頂端建立如內(nèi)容發(fā)布系統(tǒng)和基于地址的服務(wù)等應(yīng)用程 序辐宾。而且狱从,XMPP包含了針對(duì)服務(wù)器端的軟件協(xié)議,使之能與另一個(gè)進(jìn)行通話叠纹,這使得開發(fā)者更容易建立客戶應(yīng)用程序或給一個(gè)配好系統(tǒng)添加功能季研。
2、 定義:
XMPP(可擴(kuò)展消息處理現(xiàn)場協(xié)議)是基于可擴(kuò)展標(biāo)記語言(XML)的協(xié)議誉察,它用于即時(shí)消息(IM)以及在線現(xiàn)場探測与涡。它在促進(jìn)服務(wù)器之間的準(zhǔn)即時(shí)操作。這個(gè)協(xié)議可能最終允許因特網(wǎng)用戶向因特網(wǎng)上的其他任何人發(fā)送即時(shí)消息,即使其操作系統(tǒng)和瀏覽器不同驼卖。
XMPP的前身是Jabber氨肌, 一個(gè)開源形式組織產(chǎn)生的網(wǎng)絡(luò)即時(shí)通信協(xié)議。XMPP目前被IETF國際標(biāo)準(zhǔn)組織完成了標(biāo)準(zhǔn)化工作酌畜。標(biāo)準(zhǔn)化的核心結(jié)果分為兩部分怎囚;
1、核心的XML流傳輸協(xié)議
基于XML FreeEIM流傳輸?shù)募磿r(shí)通訊擴(kuò)展應(yīng)用
XMPP的核心XML流傳輸協(xié)議的定義使得XMPP能夠在一個(gè)比以往網(wǎng)絡(luò)通信協(xié)議更規(guī)范的平臺(tái)上桥胞。借助于XML易于解析和閱讀的特性恳守,使得XMPP的協(xié)議能夠非常漂亮。
2贩虾、XMPP的即時(shí)通訊擴(kuò)展應(yīng)用
這部分是根據(jù)IETF在這之前對(duì)即時(shí)通訊的一個(gè)抽象定義的催烘,與其他業(yè)已得到廣泛使用的即時(shí)通訊協(xié)議,諸如AIM缎罢,QQ等有功能完整伊群,完善等先進(jìn)性。
在IETF 中屁使,把IM協(xié)議劃分為四種協(xié)議在岂,即時(shí)信息和出席協(xié)議(Instant Messaging and Presence Protocol, IMPP)、出席和即時(shí)信息協(xié)議(Presence and Instant Messaging Protocol, PRIM)蛮寂、針對(duì)即時(shí)信息和出席擴(kuò)展的會(huì)話發(fā)起協(xié)議(Session Initiation Protocol for Instant Messaging and Presence Leveraging Extensions, SIMPLE)蔽午,以及可擴(kuò)展的消息出席協(xié)議(XMPP)。最初研發(fā)IMPP 也是為了創(chuàng)建一種標(biāo)準(zhǔn)化的協(xié)議酬蹋,但是今天及老,IMPP 已經(jīng)發(fā)展成為基本協(xié)議單元,定義所有即時(shí)通信協(xié)議應(yīng)該支持的核心功能集范抓。
3骄恶、 XMPP協(xié)議的優(yōu)點(diǎn)
a. XMPP 協(xié)議是公開的,由JSF開源社區(qū)組織開發(fā)的匕垫。XMPP 協(xié)議并不屬于任何的機(jī)構(gòu)和個(gè)人僧鲁,而是屬于整個(gè)社區(qū),這一點(diǎn)從根本上保證了其開放性象泵。
b. XMPP 協(xié)議具有良好的擴(kuò)展性寞秃。在XMPP 中,即時(shí)消息和到場信息都是基于XML 的結(jié)構(gòu)化信息偶惠,這些信息以XML 節(jié)(XML Stanza)的形式在通信實(shí)體間交換春寿。XMPP 發(fā)揮了XML 結(jié)構(gòu)化數(shù)據(jù)的通用傳輸層的作用,它將出席和上下文敏感信息嵌入到XML 結(jié)構(gòu)化數(shù)據(jù)中忽孽,從而使數(shù)據(jù)以極高的效率傳送給最合適的資源绑改⌒淮玻基于XML 建立起來的應(yīng)用具有良好的語義完整性和擴(kuò)展性。
c. 分布式的網(wǎng)絡(luò)架構(gòu)厘线。XMPP 協(xié)議都是基于Client/Server 架構(gòu)识腿,但是XMPP協(xié)議本身并沒有這樣的限制。網(wǎng)絡(luò)的架構(gòu)和電子郵件十分相似皆的,但沒有結(jié)合任何特定的網(wǎng)絡(luò)架構(gòu)覆履,適用范圍非常廣泛。
d. XMPP 具有很好的彈性费薄。XMPP 除了可用在即時(shí)通信的應(yīng)用程序硝全,還能用在網(wǎng)絡(luò)管理、內(nèi)容供稿楞抡、協(xié)同工具伟众、檔案共享、游戲召廷、遠(yuǎn)端系統(tǒng)監(jiān)控等凳厢。
e. 安全性。XMPP在Client-to-Server通信竞慢,和Server-to-Server通信中都使用TLS (Transport Layer Security)協(xié)議作為通信通道的加密方法先紫,保證通信的安全。任何XMPP服務(wù)器可以獨(dú)立于公眾XMPP網(wǎng)絡(luò)(例如在企業(yè)內(nèi)部網(wǎng)絡(luò)中)筹煮,而使用 SASL及TLS等技術(shù)更加增強(qiáng)了通信的安全性遮精。如下圖所示:
4、 XMPP協(xié)議的組成
主要的XMPP 協(xié)議范本及當(dāng)今應(yīng)用很廣的XMPP 擴(kuò)展:
l RFC 3920 XMPP(新的RFC6120):核心败潦。定義了XMPP 協(xié)議框架下應(yīng)用的網(wǎng)絡(luò)架構(gòu)本冲,引入了XML Stream(XML 流)與XML Stanza(XML 節(jié)),并規(guī)定XMPP 協(xié)議在通信過程中使用的XML 標(biāo)簽劫扒。使用XML 標(biāo)簽從根本上說是協(xié)議開放性與擴(kuò)展性的需要檬洞。此外,在通信的安全方面沟饥,把TLS 安全傳輸機(jī)制與SASL 認(rèn)證機(jī)制引入到內(nèi)核添怔,與XMPP 進(jìn)行無縫的連接,為協(xié)議的安全性贤旷、可靠性奠定了基礎(chǔ)广料。Core 文檔還規(guī)定了錯(cuò)誤的定義及處理、XML 的使用規(guī)范遮晚、JID(Jabber Identifier性昭,Jabber 標(biāo)識(shí)符)的定義拦止、命名規(guī)范等等县遣。所以這是所有基于XMPP 協(xié)議的應(yīng)用都必需支持的文檔糜颠。
l RFC 3921:用戶成功登陸到服務(wù)器之后,發(fā)布更新自己的在線好友管理萧求、發(fā)送即時(shí)聊天消息等業(yè)務(wù)其兴。所有的這些業(yè)務(wù)都是通過三種基本的XML 節(jié)來完成的:IQ Stanza(IQ 節(jié)), Presence Stanza(Presence 節(jié)), Message Stanza(Message 節(jié))。RFC3921 還對(duì)阻塞策略進(jìn)行了定義夸政,定義是多種阻塞方式元旬。可以說守问,RFC3921 是RFC3920 的充分補(bǔ)充匀归。兩個(gè)文檔結(jié)合起來,就形成了一個(gè)基本的即時(shí)通信協(xié)議平臺(tái)耗帕,在這個(gè)平臺(tái)上可以開發(fā)出各種各樣的應(yīng)用穆端。
l XEP-0030 服務(wù)搜索。一個(gè)強(qiáng)大的用來測定XMPP 網(wǎng)絡(luò)中的其它實(shí)體所支持特性的協(xié)議仿便。
l XEP-0115 實(shí)體性能体啰。XEP-0030 的一個(gè)通過即時(shí)出席的定制,可以實(shí)時(shí)改變交變廣告功能嗽仪。
l XEP-0045 多人聊天荒勇。一組定義參與和管理多用戶聊天室的協(xié)議,類似于Internet 的Relay Chat闻坚,具有很高的安全性沽翔。
l XEP-0096 文件傳輸。定義了從一個(gè)XMPP 實(shí)體到另一個(gè)的文件傳輸鲤氢。
l XEP-0124 HTTP 綁定搀擂。將XMPP 綁定到HTTP 而不是TCP,主要用于不能夠持久的維持與服務(wù)器TCP 連接的設(shè)備卷玉。
l XEP-0166 Jingle哨颂。規(guī)定了多媒體通信協(xié)商的整體架構(gòu)。
l XEP-0167 Jingle Audio Content Description Format相种。定義了從一個(gè)XMPP 實(shí)體到另一個(gè)的語音傳輸過程威恼。
l XEP-0176 Jingle ICE(Interactive Connectivity Establishment)Transport。ICE傳輸機(jī)制寝并,文件解決了如何讓防火墻或是NAT(Network Address Translation)保護(hù)下的實(shí)體建立連接的問題箫措。
l XEP-0177 Jingle Raw UDP Transport。純UDP 傳輸機(jī)制衬潦,文件講述了如何在沒有防火墻且在同一網(wǎng)絡(luò)下建立連接的斤蔓。
l XEP-0180 Jingle Video Content Description Format。定義了從一個(gè)XMPP 實(shí)體到另一個(gè)的視頻傳輸過程镀岛。
l XEP-0181 Jingle DTMF(Dual Tone Multi-Frequency)弦牡。
l XEP-0183 Jingle Telepathy Transport Method友驮。
5、 XMPP協(xié)議網(wǎng)絡(luò)架構(gòu)
XMPP是一個(gè)典型的C/S架構(gòu)驾锰,而不是像大多數(shù)即時(shí)通訊軟件一樣卸留,使用P2P客戶端到客戶端的架構(gòu)垛玻,也就是說在大多數(shù)情況下桑腮,當(dāng)兩個(gè)客戶端進(jìn)行通訊時(shí), 他們的消息都是通過服務(wù)器傳遞的(也有例外厦取,例如在兩個(gè)客戶端傳輸文件時(shí)).采用這種架構(gòu)赏酥,主要是為了簡化客戶端喳整,將大多數(shù)工作放在服務(wù)器端進(jìn)行,這樣裸扶, 客戶端的工作就比較簡單算柳,而且,當(dāng)增加功能時(shí)姓言,多數(shù)是在服務(wù)器端進(jìn)行.XMPP服務(wù)的框架結(jié)構(gòu)如下圖所示.XMPP中定義了三個(gè)角色瞬项,XMPP客戶 端,XMPP服務(wù)器何荚、網(wǎng)關(guān).通信能夠在這三者的任意兩個(gè)之間雙向發(fā)生.服務(wù)器同時(shí)承擔(dān)了客戶端信息記錄囱淋、連接管理和信息的路由功能.網(wǎng)關(guān)承擔(dān)著與異構(gòu)即時(shí) 通信系統(tǒng)的互聯(lián)互通,異構(gòu)系統(tǒng)可以包括SMS(短信)餐塘、MSN妥衣、ICQ等.基本的網(wǎng)絡(luò)形式是單客戶端通過TCP/IP連接到單服務(wù)器,然后在之上傳輸 XML戒傻,工作原理是:
(1) 點(diǎn)連接到服務(wù)器税手;
(2)服務(wù)器利用本地目錄系統(tǒng)中的證書對(duì)其認(rèn)證;
(3) 點(diǎn)指定目標(biāo)地址需纳,讓服務(wù)器告知目標(biāo)狀態(tài)芦倒;
(4) 務(wù)器查找、連接并進(jìn)行相互認(rèn)證不翩;
(5) 點(diǎn)之間進(jìn)行交互兵扬;
6、 XMPP客戶端
XMPP 系統(tǒng)的一個(gè)設(shè)計(jì)標(biāo)準(zhǔn)是必須支持簡單的客戶端口蝠。事實(shí)上器钟,XMPP 系統(tǒng)架構(gòu)對(duì)客戶端只有很少的幾個(gè)限制。一個(gè)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 客戶端必須實(shí)現(xiàn)以下標(biāo)準(zhǔn)協(xié)議(XEP-0211):
RFC3920 核心協(xié)議Core
RFC3921 即時(shí)消息和出席協(xié)議Instant Messaging and Presence
XEP-0030 服務(wù)發(fā)現(xiàn)Service Discovery
XEP-0115 實(shí)體能力Entity Capabilities
7、 XMPP服務(wù)器
XMPP 服務(wù)器遵循兩個(gè)主要法則:
1播歼、監(jiān)聽客戶端連接伶跷,并直接與客戶端應(yīng)用程序通信;
2秘狞、與其他 XMPP 服務(wù)器通信叭莫;
XMPP開源服務(wù)器一般被設(shè)計(jì)成模塊化,由各個(gè)不同的代碼包構(gòu)成烁试,這些代碼包分別處理Session管理雇初、用戶和服務(wù)器之間的通信、服務(wù)器之間的通信减响、 DNS(Domain Name System)轉(zhuǎn)換靖诗、存儲(chǔ)用戶的個(gè)人信息和朋友名單、保留用戶在下線時(shí)收到的信息支示、用戶注冊(cè)刊橘、用戶的身份和權(quán)限認(rèn)證、根據(jù)用戶的要求過濾信息和系統(tǒng)記錄 等颂鸿。另外促绵,服務(wù)器可以通過附加服務(wù)來進(jìn)行擴(kuò)展,如完整的安全策略嘴纺,允許服務(wù)器組件的連接或客戶端選擇败晴,通向其他消息系統(tǒng)的網(wǎng)關(guān)。
基本的XMPP 服務(wù)器必須實(shí)現(xiàn)以下標(biāo)準(zhǔn)協(xié)議
RFC3920 核心協(xié)議Core
RFC3921 即時(shí)消息和出席協(xié)議Instant Messaging and Presence
XEP-0030 服務(wù)發(fā)現(xiàn)Service Discovery
8栽渴、 XMPP網(wǎng)關(guān)
XMPP 突出的特點(diǎn)是可以和其他即時(shí)通信系統(tǒng)交換信息和用戶在線狀況尖坤。由于協(xié)議不同,XMPP 和其他系統(tǒng)交換信息必須通過協(xié)議的轉(zhuǎn)換來實(shí)現(xiàn)闲擦,目前幾種主流即時(shí)通信協(xié)議都沒有公開糖驴,所以XMPP 服務(wù)器本身并沒有實(shí)現(xiàn)和其他協(xié)議的轉(zhuǎn)換,但它的架構(gòu)允許轉(zhuǎn)換的實(shí)現(xiàn)佛致。實(shí)現(xiàn)這個(gè)特殊功能的服務(wù)端在XMPP 架構(gòu)里叫做網(wǎng)關(guān)(gateway)贮缕。目前,XMPP 實(shí)現(xiàn)了和AIM俺榆、ICQ感昼、IRC、MSN Massager罐脊、RSS0.9 和Yahoo Massager 的協(xié)議轉(zhuǎn)換定嗓。由于網(wǎng)關(guān)的存在蜕琴,XMPP 架構(gòu)事實(shí)上兼容所有其他即時(shí)通信網(wǎng)絡(luò),這無疑大大提高了XMPP 的靈活性和可擴(kuò)展性宵溅。
9凌简、 XMPP地址格式
一個(gè)實(shí)體在XMPP網(wǎng)絡(luò)結(jié)構(gòu)中被稱為一個(gè)接點(diǎn),它有唯一的標(biāo)示符jabber identifier(JID)恃逻,即實(shí)體地址雏搂,用來表示一個(gè)Jabber用戶,但是也可以表示其他內(nèi)容寇损,例如一個(gè)聊天室.一個(gè)有效的JID包括一系列元素:
(1) 名(domain identifier)凸郑;
(2) 點(diǎn)(node identifier);
(3) 源(resource identifier).
它的格式是node@domain/resource矛市,node@domain芙沥,類似電子郵件的地址格式.resource用來表示接點(diǎn)不同的設(shè)備或位置,這 個(gè)是可選的浊吏,例如a在Server1上注冊(cè)了一個(gè)用戶而昨,用戶名為doom,那么a的JID就是doom@serverl找田,在發(fā)送消息時(shí)配紫,指明 doom@serverl就可以了,resource可以不用指定午阵,但a在登錄到這個(gè)Server時(shí)躺孝,fl的JID可能是doom@serverl/exodus(如果a用Exodus軟件登錄),也可能是[email=doom@serverl/psi] ? ?doom@serverl /psi[/email](如果a用psi軟件登錄).資源只用來識(shí)別屬于用戶的位置或設(shè)備等底桂,一個(gè)用戶可以同時(shí)以多種資源與同一個(gè)XMPP服務(wù)器連接植袍。
10、 XMPP消息格式
XMPP中定義了3個(gè)頂層XML元素: Message籽懦、Presence于个、IQ,下面針對(duì)這三種元素進(jìn)行介紹暮顺。
用于在兩個(gè)jabber用戶之間發(fā)送信息厅篓。Jsm(jabber會(huì)話管理器)負(fù)責(zé)滿足所有的消息,不管目標(biāo)用戶的狀態(tài)如何捶码。如果用戶在線jsm立即提交;否則jsm就存儲(chǔ)羽氮。
To : 標(biāo)識(shí)消息的接收方。
from : 指發(fā)送方的名字或標(biāo)示(id)
Text: 此元素包含了要提交給目標(biāo)用戶的信息惫恼。
結(jié)構(gòu)如下所示:
你好档押,在忙嗎
用來表明用戶的狀態(tài),如:online、away令宿、dnd(請(qǐng)勿打擾)等叼耙。當(dāng)用戶離線或改變自己的狀態(tài)時(shí),就會(huì)在stream的上下文中插入一個(gè)Presence元素粒没,來表明自身的狀態(tài).結(jié)構(gòu)如下所示:
jabber.com/contact’To = ‘yaoman @jabber.com/contact'>
Online
元素可以取下面幾種值:
Probe: 用于向接受消息方發(fā)送特殊的請(qǐng)求
subscribe: 當(dāng)接受方狀態(tài)改變時(shí)筛婉,自動(dòng)向發(fā)送方發(fā)送presence信息。
< IQ >
一種請(qǐng)求/響應(yīng)機(jī)制:從一個(gè)實(shí)體向另一個(gè)發(fā)送請(qǐng)求癞松,另外一個(gè)實(shí)體接受請(qǐng)求爽撒,并進(jìn)行響應(yīng).例如,client在stream的上下文中插入一個(gè)元素拦惋,向Server請(qǐng)求得到自己的好友列表,Server返回一個(gè)安寺,里面是請(qǐng)求的結(jié)果.
主要的屬性是type厕妖。包括:
Get :獲取當(dāng)前域值。
Set :設(shè)置或替換get查詢的值挑庶。
Result :說明成功的響應(yīng)了先前的查詢言秸。
Error: 查詢和響應(yīng)中出現(xiàn)的錯(cuò)誤。
結(jié)構(gòu)如下所示:
jabber.com/contact’id=’1364564666’Type=’result’>
XMPP通信協(xié)議
一迎捺、 Stream
http://etherx.jabber.org/streams"
xmlns="jabber:client" from="127.0.0.1" id="e38900bc" xml:lang="en"
version="1.0">
xmlns 表示通信客戶端
from 客戶端的地址(來源)
id
lang 通信語言
-->
DIGEST-MD5
PLAIN
ANONYMOUS
CRAM-MD5
http://jabber.org/features/compress">
zlib
http://jabber.org/features/iq-auth" />
http://jabber.org/features/iq-register" />
關(guān)于TSL 參考:http://www.jabbercn.org/RFC3920
1举畸、TSL協(xié)議遵循以下規(guī)則:
A、 一個(gè)遵守本協(xié)議的初始化實(shí)體必須(MUST)在初始化流的頭信息中包含一個(gè)'version'屬性并把值設(shè)為“1.0”凳枝。
B抄沮、 如果TLS握手發(fā)生在兩個(gè)服務(wù)器之間,除非服務(wù)器聲稱的DNS主機(jī)名已經(jīng)被解析岖瑰,通信不能(MUST NOT)繼續(xù)進(jìn)行叛买。
C、 當(dāng)一個(gè)遵守本協(xié)議的接收實(shí)體接收了一個(gè)初始化流(它的頭信息中包含一個(gè)'version'屬性并且值設(shè)為“1.0”)蹋订,在發(fā)送應(yīng)答流的的頭信息(其中包含 版本標(biāo)記)之后率挣,它必須發(fā)送(MUST)元素(名字空間為 'urn:ietf:params:xml:ns:xmpp-tls')以及其他它支持的流特性。
D露戒、 如果初始化實(shí)體選擇使用TLS,TLS握手必須在SASL握手之前完成椒功;這個(gè)順序用于幫助保護(hù)SASL握手時(shí)發(fā)送的認(rèn)證信息的安全,同時(shí)可以在必要的時(shí)候在TLS握手之前為SASL外部機(jī)制提供證書智什。
E动漾、 TLS握手期間,一個(gè)實(shí)體不能(MUST NOT)在流的根元素中發(fā)送任何空格符號(hào)作為元素的分隔符(在下面的TLS示例中的任何空格符都僅僅是為了便于閱讀);這個(gè)禁令用來幫助確保安全層字節(jié)精度荠锭。
F谦炬、 接收實(shí)體必須(MUST)在發(fā)送 元素的關(guān)閉符號(hào)">" 之后立刻開始TLS協(xié)商。初始化實(shí)體必須(MUST)在從接收實(shí)體接收到 元素的關(guān)閉符號(hào)">" 之后立刻開始TLS協(xié)商。
G键思、 初始化實(shí)體必須(MUST)驗(yàn)證接收實(shí)體出示的證書础爬;關(guān)于證書驗(yàn)證流程參見Certificate Validation ( 第十四章第二節(jié))。
H吼鳞、 證書必須(MUST)檢查初始化實(shí)體(比如一個(gè)用戶)提供的主機(jī)名看蚜;而不是通過DNS系統(tǒng)解析出來的主機(jī)名;例如赔桌,如果用戶指定一個(gè)主機(jī) 名"example.com"而一個(gè)DNS SRV [SRV]查詢返回"im.example.com"供炎,證書必須(MUST)檢查"example.com".如果任何種類的XMPP實(shí)體(例如客戶端或 服務(wù)器)的JID出現(xiàn)在一個(gè)證書里,它必須(MUST)表現(xiàn)為一個(gè)別名實(shí)體里面的UTF8字符串疾党,存在于subjectAltName之中音诫。如何使用 [ASN.1] 對(duì)象標(biāo)識(shí)符 "id-on-xmppAddr" 定義在本文的第五章第一節(jié)第一小節(jié)。
I雪位、 如果 TLS 握手成功了竭钝,接收實(shí)體必須(MUST) 丟棄TLS 生效之前從初始化實(shí)體得到的任何不可靠的信息
J、 如果 TLS 握手成功了雹洗,初始化實(shí)體必須(MUST) 丟棄TLS 生效之前從接收實(shí)體得到的任何不可靠的信息
K香罐、 如果 TLS 握手成功了,接收實(shí)體不能(MUST NOT)在流重新開始的時(shí)候通過提供其他的流特性來向初始化實(shí)體提供 STARTTLS 擴(kuò)展
L时肿、 如果 TLS 握手成功了庇茫,初始化實(shí)體必須(MUST)繼續(xù)進(jìn)行SASL握手
M、 如果 TLS 握手失敗了螃成,接收實(shí)體必須(MUST)終止XML流和相應(yīng)的TCP連接旦签。
N、 關(guān)于必須(MUST)支持的機(jī)制寸宏,參照 Mandatory-to-Implement Technologies (第十四章第七節(jié)) 顷霹。
2、當(dāng)一個(gè)初始化實(shí)體用TLS保護(hù)一個(gè)和接收實(shí)體之間的流击吱,其步驟如下:
A. 初始化實(shí)體打開一個(gè)TCP連接淋淀,發(fā)送一個(gè)打開的XML流頭信息(其'version'屬性設(shè)置為"1.0")給接收實(shí)體以初始化一個(gè)流。
B. 接收實(shí)體打開一個(gè)TCP連接覆醇,發(fā)送一個(gè)XML流頭信息(其'version'屬性設(shè)置為"1.0")給初始化實(shí)體作為應(yīng)答朵纷。
C. 接收實(shí)體向初始化實(shí)體提議STARTTLS范圍(包括其他支持的流特性),如果TLS對(duì)于和接收實(shí)體交互是必需的永脓,它應(yīng)該(SHOULD)在元素中包含子元素
D. 初始化實(shí)體發(fā)出STARTTLS命令(例如, 一個(gè)符合'urn:ietf:params:xml:ns:xmpp-tls'名字空間的 元素) 以通知接收實(shí)體它希望開始一個(gè)TLS握手來保護(hù)流袍辞。
E. 接收實(shí)體必須(MUST)以'urn:ietf:params:xml:ns:xmpp-tls'名字空間中的元素 或元素應(yīng)答。如果失敗常摧,接收實(shí)體必須(MUST)終止XML流和相應(yīng)的TCP連接搅吁。如果繼續(xù)進(jìn)行威创,接收實(shí)體必須 (MUST)嘗試通過TCP連接完成TLS握手并且在TLS握手完成之前不能(MUST NOT)發(fā)送任何其他XML數(shù)據(jù)。
F. 初始化實(shí)體和接收實(shí)體嘗試完成TLS握手谎懦。(要符合[TLS]規(guī)范)
G. 如果 TLS 握手不成功, 接收實(shí)體必須(MUST)終止 TCP 連接. 如果 TLS 握手成功, 初始化實(shí)體必須(MUST)發(fā)送給接收實(shí)體一個(gè)打開的XML流頭信息來初始化一個(gè)新的流(先發(fā)送一個(gè)關(guān)閉標(biāo)簽是不必要的, 因?yàn)榻邮諏?shí)體和初始化實(shí)體必須(MUST)確保原來的流在TLS握手成功之后被關(guān)閉) 肚豺。
H. 在從初始化實(shí)體收到新的流頭信息之后,接收實(shí)體必須(MUST)發(fā)送一個(gè)新的XML流頭信息給初始化實(shí)體作為應(yīng)答界拦,其中應(yīng)包含可用的特性但不包含STATRTTLS特性吸申。
http://www.cnblogs.com/hoojo/archive/2012/06/18/2553975.html
在文章開始,請(qǐng)你了解和熟悉openfire方面的相關(guān)知識(shí)享甸,這樣對(duì)你理解下面代碼以及下面代碼的用途有很好的了解截碴。同時(shí),你可能需要安裝一個(gè)簡單的CS聊天工具蛉威,來測試你的代碼是否成功的在openfire服務(wù)器上建立會(huì)話鏈接日丹,并成功的向在線用戶發(fā)送聊天消息。
必須了解:http://www.cnblogs.com/hoojo/archive/2012/05/17/2506769.html
http://www.cnblogs.com/hoojo/archive/2012/05/13/2498151.html(非windows 系統(tǒng))
可選:http://www.cnblogs.com/hoojo/archive/2012/05/17/2506845.html
http://www.cnblogs.com/hoojo/archive/2012/06/18/2553975.html
聊天軟件Spark蚯嫌,用于測試聊天消息發(fā)送是否成功哲虾,下載地址:http://www.igniterealtime.org/do... ark/spark_2_6_3.exe
然后你需要添加smack相關(guān)的jar包
smack.jar
smackx.jar
jar包下載地址:http://www.igniterealtime.org/do... ack/smack_3_2_2.zip
代碼中還用到了junit,junit jar下載地址:http://ebr.springsource.com/repo... 8.2&type=binary
下面開始代碼部分
package com.hoo.smack;
import java.util.Collection;
import java.util.Iterator;
import javax.net.SocketFactory;
import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.Message.Type;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* function: 利用Smack框架完成 XMPP 協(xié)議通信
* @author hoojo
* @createDate 2012-5-22 上午10:28:18
* @file ConnectionServerTest.java
* @package com.hoo.smack.conn
* @project jwchat
* @bloghttp://blog.csdn.net/IBM_hoojo
* @emailhoojo_@126.com
* @version 1.0
*/
public class SmackXMPPTest {
private Connection connection;
private ConnectionConfiguration config;
/** openfire服務(wù)器address */
private final static String server = "192.168.8.32";
private final void fail(Object o) {
if (o != null) {
System.out.println(o);
}
}
private final void fail(Object o, Object... args) {
if (o != null && args != null && args.length > 0) {
String s = o.toString();
for (int i = 0; i < args.length; i++) {
String item = args == null ? "" : args.toString();
if (s.contains("{" + i + "}")) {
s = s.replace("{" + i + "}", item);
} else {
s += " " + item;
}
}
System.out.println(s);
}
}
/**
* function: 初始Smack對(duì)openfire服務(wù)器鏈接的基本配置
* @author hoojo
* @createDate 2012-6-25 下午04:06:42
*/
@Before
public void init() {
try {
//connection = new XMPPConnection(server);
//connection.connect();
/** 5222是openfire服務(wù)器默認(rèn)的通信端口齐帚,你可以登錄http://192.168.8.32:9090/到管理員控制臺(tái)查看客戶端到服務(wù)器端口 */
config = new ConnectionConfiguration(server, 5222);
/** 是否啟用壓縮 */
config.setCompressionEnabled(true);
/** 是否啟用安全驗(yàn)證 */
config.setSASLAuthenticationEnabled(true);
/** 是否啟用調(diào)試 */
config.setDebuggerEnabled(false);
//config.setReconnectionAllowed(true);
//config.setRosterLoadedAtLogin(true);
/** 創(chuàng)建connection鏈接 */
connection = new XMPPConnection(config);
/** 建立連接 */
connection.connect();
} catch (XMPPException e) {
e.printStackTrace();
}
fail(connection);
fail(connection.getConnectionID());
}
@After
public void destory() {
if (connection != null) {
connection.disconnect();
connection = null;
}
}
/**
* function: ConnectionConfiguration 的基本配置相關(guān)信息
* @author hoojo
* @createDate 2012-6-25 下午04:11:25
*/
@Test
public void testConfig() {
fail("PKCS11Library: " + config.getPKCS11Library());
fail("ServiceName: {0}", config.getServiceName());
// ssl證書密碼
fail("TruststorePassword: {0}", config.getTruststorePassword());
fail("TruststorePath: {0}", config.getTruststorePath());
fail("TruststoreType: {0}", config.getTruststoreType());
SocketFactory socketFactory = config.getSocketFactory();
fail("SocketFactory: {0}", socketFactory);
/*try {
fail("createSocket: {0}", socketFactory.createSocket("localhost", 3333));
} catch (IOException e) {
e.printStackTrace();
}*/
}
/**
* function: Connection 基本方法信息
* @author hoojo
* @createDate 2012-6-25 下午04:12:04
*/
@Test
public void testConnection() {
/** 用戶管理 */
AccountManager accountManager = connection.getAccountManager();
for (String attr : accountManager.getAccountAttributes()) {
fail("AccountAttribute: {0}", attr);
}
fail("AccountInstructions: {0}", accountManager.getAccountInstructions());
/** 是否鏈接 */
fail("isConnected:", connection.isConnected());
fail("isAnonymous:", connection.isAnonymous());
/** 是否有權(quán)限 */
fail("isAuthenticated:", connection.isAuthenticated());
fail("isSecureConnection:", connection.isSecureConnection());
/** 是否使用壓縮 */
fail("isUsingCompression:", connection.isUsingCompression());
}
/**
* function: 用戶管理器
* @author hoojo
* @createDate 2012-6-25 下午04:22:31
*/
@Test
public void testAccountManager() {
AccountManager accountManager = connection.getAccountManager();
for (String attr : accountManager.getAccountAttributes()) {
fail("AccountAttribute: {0}", attr);
}
fail("AccountInstructions: {0}", accountManager.getAccountInstructions());
fail("supportsAccountCreation: {0}", accountManager.supportsAccountCreation());
try {
/** 創(chuàng)建一個(gè)用戶boy妒牙,密碼為boy彼哼;你可以在管理員控制臺(tái)頁面http://192.168.8.32:9090/user-summary.jsp查看用戶/組的相關(guān)信息对妄,來查看是否成功創(chuàng)建用戶 */
accountManager.createAccount("boy", "boy");
/** 修改密碼 */
accountManager.changePassword("abc");
} catch (XMPPException e) {
e.printStackTrace();
}
}
@Test
public void testUser() {
try {
/** 用戶登陸,用戶名敢朱、密碼 */
connection.login("hoojo", "hoojo");
} catch (XMPPException e) {
e.printStackTrace();
}
/** 獲取當(dāng)前登陸用戶 */
fail("User:", connection.getUser());
/** 所有用戶組 */
Roster roster = connection.getRoster();
/** 好友用戶組剪菱,你可以用Spark添加用戶好友,這樣這里就可以查詢到相關(guān)的數(shù)據(jù) */
Collection rosterEntiry = roster.getEntries();
Iterator iter = rosterEntiry.iterator();
while (iter.hasNext()) {
RosterEntry entry = iter.next();
fail("Groups: {0}, Name: {1}, Status: {2}, Type: {3}, User: {4}", entry.getGroups(), entry.getName(), entry.getStatus(), entry.getType(), entry);
}
fail("-------------------------------");
/** 未處理拴签、驗(yàn)證好友孝常,添加過的好友,沒有得到對(duì)方同意 */
Collection unfiledEntries = roster.getUnfiledEntries();
iter = unfiledEntries.iterator();
while (iter.hasNext()) {
RosterEntry entry = iter.next();
fail("Groups: {0}, Name: {1}, Status: {2}, Type: {3}, User: {4}", entry.getGroups(), entry.getName(), entry.getStatus(), entry.getType(), entry);
}
}
@Test
@SuppressWarnings("static-access")
public void testPacket() {
try {
connection.login("hoojo", "hoojo");
} catch (XMPPException e) {
e.printStackTrace();
}
//Packet packet = new Data(new DataPacketExtension("jojo@" + server, 2, "this is a message"));
//connection.sendPacket(packet);
/** 更改用戶狀態(tài)蚓哩,available=true表示在線构灸,false表示離線,status狀態(tài)簽名岸梨;當(dāng)你登陸后喜颁,在Spark客戶端軟件中就可以看到你登陸的狀態(tài) */
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Q我吧");
connection.sendPacket(presence);
Session session = new Session();
String sessid = session.nextID();
connection.sendPacket(session);
/** 向jojo@192.168.8.32 發(fā)送聊天消息,此時(shí)你需要用Spark軟件登陸jojo這個(gè)用戶曹阔,
* 這樣代碼就可以向jojo這個(gè)用戶發(fā)送聊天消息半开,Spark登陸的jojo用戶就可以接收到消息
**/
/** Type.chat 表示聊天,groupchat多人聊天赃份,error錯(cuò)誤寂拆,headline在線用戶奢米; */
Message message = new Message("jojo@" + server, Type.chat);
//Message message = new Message(sessid, Type.chat);
message.setBody("h!~ jojo, I'am is hoojo!");
connection.sendPacket(message);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* function: 測試聊天消息管理類
* @author hoojo
* @createDate 2012-6-25 下午05:03:23
*/
@Test
public void testChatManager() {
/** 設(shè)置狀態(tài) */
try {
connection.login("hoojo", "hoojo");
} catch (XMPPException e) {
e.printStackTrace();
}
/** 設(shè)置狀態(tài) */
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("Q我吧");
connection.sendPacket(presence);
/** 獲取當(dāng)前登陸用戶的聊天管理器 */
ChatManager chatManager = connection.getChatManager();
/** 為指定用戶創(chuàng)建一個(gè)chat,MyMessageListeners用于監(jiān)聽對(duì)方發(fā)過來的消息? */
Chat chat = chatManager.createChat("jojo@" + server, new MyMessageListeners());
try {
/** 發(fā)送消息 */
chat.sendMessage("h!~ jojo……");
/** 用message對(duì)象發(fā)送消息 */
Message message = new Message();
message.setBody("message");
message.setProperty("color", "red");
chat.sendMessage(message);
} catch (XMPPException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* function: 消息監(jiān)聽器纠永,用戶監(jiān)聽對(duì)方發(fā)送的消息鬓长,也可以想對(duì)方發(fā)送消息
* @author hoojo
* @createDate 2012-6-25 下午05:05:31
* @file SmackXMPPTest.java
* @package com.hoo.smack
* @project jwchat
* @bloghttp://blog.csdn.net/IBM_hoojo
* @emailhoojo_@126.com
* @version 1.0
*/
class MyMessageListeners implements MessageListener {
public void processMessage(Chat chat, Message message) {
try {
/** 發(fā)送消息 */
chat.sendMessage("dingding……" + message.getBody());
} catch (XMPPException e) {
e.printStackTrace();
}
/** 接收消息 */
fail("From: {0}, To: {1}, Type: {2}, Sub: {3}", message.getFrom(), message.getTo(), message.getType(), message.toXML());
/*Collection bodys =? message.getBodies();
for (Body body : bodys) {
fail("bodies[{0}]", body.getMessage());
}
//fail(message.getLanguage());
//fail(message.getThread());
//fail(message.getXmlns());*/
fail("body: ", message.getBody());
}
}
}
好了,這些都是smack的基本功能渺蒿,還有更多的東西需要研究痢士,下次有機(jī)會(huì)再分享!
http://www.cnblogs.com/hoojo/archive/2012/06/25/2561576.html