IM的實現原理
在我最初學習編程的時候,曾經用JAVA實現了一個最簡單版的IM通信,即經過Socket創建兩臺電腦之間的鏈接,而後發送IO流來進行即時通信,咱們如今所使用的IM軟件儘管看上去很是複雜,可是基本的原理和以上的差很少,無非是採用服務器<>客戶端的架構,經過登錄到服務器來獲取我的資料和好友,而後聊天時直接經過IP和好友進行即時通信。node
XMPP協議的網絡架構
XMPP是一個典型的C/S架構,而不是像大多數即時通信軟件同樣,使用P2P客戶端到客戶端的架構,也就是說在大多數狀況下,當兩個客戶端進行通信時,他們的消息都是經過服務器傳遞的(也有例外,例如在兩個客戶端傳輸文件時).採用這種架構,主要是爲了簡化客戶端,將大多數工做放在服務器端進行,這樣,客戶端的工做就比較簡單,並且,當增長功能時,多數是在服務器端進行.XMPP服務的框架結構以下圖所示.XMPP中定義了三個角色,XMPP客戶端,XMPP服務器、網關.通訊可以在這三者的任意兩個之間雙向發生.服務器同時承擔了客戶端信息記錄、鏈接管理和信息的路由功能.網關承擔着與異構即時通訊系統的互聯互通,異構系統能夠包括SMS(短信)、MSN、ICQ等.基本的網絡形式是單客戶端經過TCP/IP鏈接到單服務器,而後在之上傳輸XML,工做原理是:編程
節點鏈接到服務器;
服務器利用本地目錄系統中的證書對其認證;
節點指定目標地址,讓服務器告知目標狀態;
服務器查找、鏈接並進行相互認證;
節點之間進行交互。
XMPP協議的傳輸是經過XML文件來傳輸的,而且不是相似於QQ的點對點通信,而是客戶端到服務器再到客戶端的方式來實現,以上過程的一個簡單的XMPP通信流程能夠以下:安全
首先,由客戶端鏈接到服務器,客戶端經過IO流發送一段XML文件,在文件中包含了自身的用戶名和密碼。
服務器端接收到客戶端的XML文件,從中獲取用戶名和密碼進行驗證,若是驗證成功,服務器會發送一個XML文件給客戶端代表已經登陸成功。
登錄成功後,客戶端能夠經過發送一個獲取好友名單的XML文件,服務器會將當前用戶的好友以XML文件傳到客戶端。
客戶端選擇一個好友,向其發送信息(實際上是向服務器發送,服務器收到後會轉發給對應的好友),好友收到。
經過以上的流程,一此基本的通信得以達成。服務器
Spark架構網絡
(上圖爲XMPP的一個實現Openfire+Smack+Spark的實現)架構
XMPP協議的一些概念
經過以上簡介,咱們瞭解了XMPP協議的基本流程,下面來了解一個XML中一些基本的概念。框架
XMPP地址
一個實體在XMPP網絡結構中被稱爲一個節點,它有惟一的標示符jabber identifier(JID),即實體地址,用來表示一個用戶,可是也能夠表示其餘內容,例如一個聊天室.一個有效的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服務器鏈接。dom
XMPP的XML流
即時通信的聊天是指上就是二進制流或者字符流。在之前這些命令要麼用2進制的形式發送(好比QQ),要麼用純文本指令加空格加參數加換行苻的方式發送(好比MSN)。而XMPP傳輸的即時通信指令的邏輯與以往相仿,只是協議的形式變成了XML格式的純文本。這不但使得解析容易了,人也容易閱讀了,方便了開發和查錯。而XMPP的核心部分就是一個在網絡上分片段發送XML的流協議。這個流協議是XMPP的即時通信指令的傳遞基礎,也是一個很是重要的能夠被進一步利用的網絡基礎協議。因此能夠說,XMPP用TCP傳的是XML流。 ide
舉個例子看看所謂的XML流是什麼樣子的? 學習
客戶端:<?xml version='1.0'?>
<stream:stream
to='example.com'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
服務器:<?xml version='1.0'?>
<stream:stream
from='example.com'
id='someid'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'
version='1.0'>
...其餘通訊...
客戶端:<message from='juliet@example.com'
xml:lang='en'>
客戶端: <body>Art thou not Romeo, and a Montague?</body>
客戶端:</message>
服務器:<message from='romeo@example.net'
xml:lang='en'>
服務器:<body>Neither, fair saint, if either thee dislike.</body>
服務器:</message>
客戶端:</stream:stream>
服務器:</stream:stream>
以文檔的觀點來看,客戶端或服務器發送的全部XML文本連綴在一塊兒,從<stream>到</stream>構成了一個完整的XML文檔。其中的stream標籤就是所謂的XML Stream。在<stream>與</stream>中間的那些<message>...</message>這樣的XML元素就是所謂的XML Stanza(XML節)。XMPP核心協議通訊的基本模式就是先創建一個stream,而後協商一堆安全之類的東西,中間通訊過程就是客戶端發送XML Stanza,一個接一個的。服務器根據客戶端發送的信息以及程序的邏輯,發送XML Stanza給客戶端。可是這個過程並非一問一答的,任什麼時候候都有可能從一個方發信給另一方。通訊的最後階段是</stream>關閉流,關閉TCP/IP鏈接。
XML節
XML節經過XML流來發送,XMPP定義了三種頂級XML節
<iq />
<message />
<presence />
XMPP給這三種節定義了五種通用屬性
to
from
id
type
xml:lang
to屬性指定接收節的JID。
from屬性指定發送者的JID。
id屬性是可選的。而且,在接收應用(一般是一個服務器)中是惟一的。注意:流ID多是嚴格安全的,而且所以必須是即不能預測也不能重複的
type屬性指定目的或消息上下文,出席或IQ節的詳細信息。iq節的type屬性有:Error,Get,Result,Set; presence節的type屬性有:Available,Subscribe,Subscribed,Unsubscribe, Unsubscribed,Unavailable,Probe,Error,Invisible; message節的type屬性有:Chat,Error,GroupChat,Headline,Normal
xml:lang屬性值指定任意可讀XML字符數據的缺省語言
<message />節定義了消息語義,<message />節可被看做「推」機制,一個實體推信息給其它實體,與EMAIL系統中發生的通訊相似。全部消息節應該擁有‘to’屬性,指定有意的消息接收者;根據接收到那樣的一個節,服務器應該路由或傳送它到有意的接收者。
<presence />節定義了出席語義,<presence />節可被看做基本廣播或「出版-訂閱」機制,多實體收到他們已訂閱(在這種狀況下,網絡可利用信息)實體的信息。總的來講,出版實體應該發送一個不帶‘to’屬性的出席節,在這種狀況下,與此實體相連的服務器應該廣播給全部訂閱實體。然而,一個出版實體也可能發送一個帶有‘to’屬性的出席節,此種狀況下,服務器應該路由或傳送節到有意的接收者。
<iq />節定義了請求語義,<iq />節可被看做一個請求-響應機制,與[HTTP]在某些方面類似。IQ語義讓一個實體向其它實體請求或接收其它實體的響應成爲可能。請求與響應的數據內容由IQ無素的直接子元素的命名空間聲明定義,而且,交互由請求實體經過使用