XMPP文件传输(XEP-0096协议说明)
XMPP XEP-0096協(xié)議是XMPP中的文件傳輸協(xié)議。
? ?? ? 關(guān)于文件傳輸,在xmpp協(xié)議中有不少協(xié)議可以實現(xiàn),而XEP-0096協(xié)議是其中非常簡單的一個協(xié)議。由于郵件被刪,我的代碼demo丟失,因此只能在這里給大家講一下其中的邏輯實現(xiàn),大家可以以此來寫出代碼。
? ?? ? 首先申明一下,以下是我個人對XEP-0096協(xié)議的一些認識和解釋,如有疑問,請發(fā)郵件到lizhanzhishang@gmail.com ,歡迎交流~
? ?? ? 我們根據(jù)openfire服務器做開發(fā),但是服務器在這里只是起路由尋址和轉(zhuǎn)發(fā)的作用,實質(zhì)上是完全點對點的通信,數(shù)據(jù)處理由客戶端來做。
? ?? ? 我們可以舉一個栗子,有兩部手機,互相之間使用message協(xié)議傳遞信息的完整message XML數(shù)據(jù),可以看看一個客戶端發(fā)送的是什么信息,另一個客戶端接收的又是什么message信息,要是一樣,說明的是服務器是轉(zhuǎn)發(fā)的數(shù)據(jù),要是不一樣的 話,則可能帶有IQ ,MSG,Pr信息。(但是總是有例外的,服務器也要對連接的數(shù)據(jù)做一些心跳包。)
? ?? ? 下面是一組請求(一方發(fā)出“發(fā)送文件”請求,接收方發(fā)出“拒絕接受”請求):
? ?? ? 這是”發(fā)送文件”的一段數(shù)據(jù)請求,(圖片小,可以雙擊放大)
? ?? ?將接受方拒絕接受文件的信息返回給發(fā)送方:
? ?? ?就此請求完畢,一方發(fā)出了“發(fā)送文件”的請求,另一方“拒絕”了這個請求。
? ?? ?這里有一個完整的數(shù)據(jù)傳輸協(xié)議,在官方的文檔上是這樣寫的:
? ?? ?上面的意思是說文件傳輸實際上是有協(xié)議XEP-0065和XEP-0047來進行的,而XEP-0096實際是傳輸IQ的消息協(xié)議,真正的傳輸數(shù)據(jù)并不 在次協(xié)議中,實現(xiàn)文件傳輸協(xié)議必須是full JID而且要求接收方在線。如果”to”(接收端), ”from”(發(fā)送端) 不是一個full JID,服務器就會發(fā)送error信息到”發(fā)送端”,說明服務器現(xiàn)在出現(xiàn)異常問題。
? ?? ?現(xiàn)在我們來說說在傳輸消息的時候,該怎么具體組織消息:
? ?? ?我們可以用IQ或者Message來發(fā)送數(shù)據(jù)。下面是我截取的文檔中我覺得相當重要的部分:
? ?? ?上面說啥呢,我英語也菜,但是能看懂一點2個關(guān)鍵點,一個是base64-encoding,block-size這個2個關(guān)鍵的單詞,說明我們在遇到 大文件的情況下是進行分塊發(fā)送的,每塊的數(shù)據(jù)都是一定字節(jié)的,例如,我們發(fā)送數(shù)據(jù)1024字節(jié),但是那個流怎么發(fā)送呢,都是二進制的。我們直接發(fā)送呢,數(shù) 據(jù)太大,不好整的,再則直接轉(zhuǎn)String呢,那也是有問題的,因為String遇到’\o’就說明數(shù)據(jù)結(jié)束,會使數(shù)據(jù)漏掉很多。 文檔中告訴我們,將發(fā)送的文件轉(zhuǎn)換為base64之后再轉(zhuǎn)為String類型,放入IQ或者Message數(shù)據(jù)格式中發(fā)送。關(guān)于base64的理論資料在 這里:http://zh.wikipedia.org/zh-cn/Base64=
? ?? ?下面是一個數(shù)據(jù)實例:
? ?? ?參考的url地址:http://xmpp.org/extensions/xep-0096.html
It is RECOMMENDED to use IQ stanzas when sending data packets. However, an application MAY use message stanzas instead. If message stanzas are used when sending data packets, the sender SHOULD also useAdvanced Message Processing (XEP-0079) [8] or some other stanza flow-control method. For proper tracking of delivery and processing errors related to data packets, the 'id' attribute SHOULD be used with message stanzas.
? ?? ?上面的base64數(shù)據(jù)不一定用IQ發(fā)送,還可以用Message發(fā)送。只是在參數(shù)上有個改變一下就可以,哈哈。
? ?? ?例子如下所示:
? ?? ?突然想起一件事情。。。在發(fā)送文件的時候,會有一個帶<si >標簽的數(shù)據(jù)段,這個數(shù)據(jù)段有id。這個id很重要,是必須要保存的。主要用在傳輸數(shù)據(jù)的時候,要是這個sid要是沒有帶上,那服務器就會返回錯誤信息給文件發(fā)送方。
? ?? ?還有個小事情,我當初解析命名空間的時候,以為是一般屬性,總是解析不出來。
最后發(fā)現(xiàn)有專門解析命名空間的東西,大家可以去google下。。。
? ?? ?下面是進行文件傳輸?shù)腦EP-0096協(xié)議的完整xml例子:
數(shù)據(jù)協(xié)議都是人定的,哈哈
文件發(fā)送方:
? ?? ?我們可以對此IQ數(shù)據(jù)段解析,當發(fā)現(xiàn)file 標簽的命名空間是http://jabber.org/protocol/si/profile/file-transfer的 時候 ,則表明這是“文件傳輸”消息請求。說明有人要傳文件了。對于這個xml請求,我們在提取數(shù)據(jù)的時候必須提取<si>標簽的ID。這個ID很 重要,是下面的sid傳輸數(shù)據(jù)的重要參數(shù),也是判斷是否是同一個數(shù)據(jù)流的依據(jù)。還有就是提取mine-type標簽內(nèi)容,這個是我們用來判斷接收的是何種 文件,并以此判斷創(chuàng)建該類型文件,把將要傳來的數(shù)據(jù)寫入這個文件,還有就是size標簽內(nèi)容,來檢驗我們接收的文件是否完整。
下面是一個完整的沒有進行base64轉(zhuǎn)換的數(shù)據(jù)請求:
文件接收方:
? ?? ?這里說明,我要接受的數(shù)據(jù)是什么協(xié)議,主要在file var這個參數(shù):stream-method
<x submit>這個表明我要接受數(shù)據(jù),你可以發(fā)給我了。
發(fā)送文件方:
? ?? ?其實也要實現(xiàn)這個xml的,我不知道,當我接受數(shù)據(jù)之后,為什么要查詢對方的機器名字,和一些基本數(shù)據(jù),這可能是進行確認。
? ?? ?接受方發(fā)出本機基本信息,主要有3個參數(shù),category="client" name="Smack" type="pc"
? ?? ?查詢之后就開始要發(fā)數(shù)據(jù)了,哈哈。
? ?? ?發(fā)出數(shù)據(jù)肯定要打開流,發(fā)送數(shù)據(jù)結(jié)束也要關(guān)閉流的,哈哈
發(fā)送方發(fā)送打開消息:
? ?? ?這個xml雖然很少,但是每個數(shù)據(jù)都很重要呢。Open的命名空間很熟悉那。其實這個就是前面剛開始接受數(shù)據(jù)file里的value,block- size說的是,我每次傳數(shù)據(jù)都是以4096字節(jié)發(fā)送一個數(shù)據(jù)流。 這個sid就是發(fā)送方發(fā)送請求文件的那個<si>標簽的id。都是相同的,同時還有一個重要的東西,stanza="iq"這個,相當?shù)闹?要,這個標簽告訴對方,我要以IQ數(shù)據(jù)類型發(fā)送數(shù)據(jù),這里也可以用message代替iq。前面我已經(jīng)提及到。
下面的是message發(fā)送base64數(shù)據(jù),如果stanza="message” 自己可以參照IQ發(fā)送base64數(shù)據(jù)。過程基本一樣,就是iq變成message而已:
接受方數(shù)據(jù)xml:
? ?? ? 上面的2個IQ是順序發(fā)送的,不可逆,第一個是主要告訴對方。同時,那3個參數(shù)是上上面的一樣的,要不是無法接收到額,還有一些對特征解釋,說明傳輸?shù)目梢阅男┝鳌?br />然后緊接著告訴對方,我可以解釋數(shù)據(jù)了。
發(fā)送方開始發(fā)數(shù)據(jù)了,哈哈:
? ?? ?這個data的value,是前面的數(shù)據(jù)塊,4096字節(jié)base64加密數(shù)據(jù)。如果數(shù)據(jù)base64大于這個塊。我們接到這個數(shù)據(jù)首先要base64解密之后,再寫入剛才建立的文件中,
Sid是上面我們說的第一次si 標簽的id。不能改變,更不能為null。也不要不設(shè)置,不然服務器就會返回錯誤信息。 Seq是從0開始的,如果還有流就會依次遞增的,
如果接受處理完畢,就發(fā)送一個iq。說明接受完成??
說明一下哈,data里的數(shù)據(jù)被我刪掉N多,我這主要是說明用。
接受方:
? ?? ?發(fā)一個一個4096字節(jié)base64加密數(shù)據(jù)。這個是源文件base64加密偏移的數(shù)據(jù)。
? ?? ?上面的seq變成1了,而sid依然沒變。接受完成處理后,一樣要回復一下,告訴他,可以繼續(xù)傳數(shù)據(jù)了。
? ?? ?最后就是base64加密完成傳輸,要colse掉數(shù)據(jù)。
? ?? ?發(fā)送方關(guān)閉流,這個sid依舊沒有變,協(xié)議是這樣規(guī)定的:
? ?? ?好吧,我知道你關(guān)閉流了。我們之間的文件傳輸完成了:
寫了幾個小時分析,真的累。哎,下面貼出完整的流程xml
下面是整個對話階段的xml數(shù)據(jù): A:發(fā)送方
B:接收方 A:
<iq id="x36vr-54" to="zhufu@domian/android" from="saonian@domian/android" type="set">
??<si xmlns="http://jabber.org/protocol/si" id="jsi_3326887048779603188" mime-type="image/png" profile="http://jabber.org/protocol/si/profile/file-transfer">
? ? <file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="image_9T.png" size="5204">
? ?? ?<desc>Sending file</desc>
? ? </file>
? ? <feature xmlns="http://jabber.org/protocol/feature-neg">
? ?? ?<x xmlns="jabber:x:data" type="form">
? ?? ???<field var="stream-method" type="list-single">
? ?? ?? ? <option>
? ?? ?? ?? ?<value>http://jabber.org/protocol/bytestreams</value>
? ?? ?? ? </option>
? ?? ?? ? <option>
? ?? ?? ?? ?<value>http://jabber.org/protocol/ibb</value>
? ?? ?? ? </option>
? ?? ???</field>
? ?? ?</x>
? ? </feature>
??</si>
</iq>
復制代碼
B:
<iq id="x36vr-54" to="saonian@domian/android" from="zhufu@domian/android" type="result">
??<si xmlns="http://jabber.org/protocol/si">
? ? <feature xmlns="http://jabber.org/protocol/feature-neg">
? ?? ?<x xmlns="jabber:x:data" type="submit">
? ?? ???<field var="stream-method">
? ?? ?? ? <value>http://jabber.org/protocol/bytestreams</value>
? ?? ?? ? <value>http://jabber.org/protocol/ibb</value>
? ?? ???</field>
? ?? ?</x>
? ? </feature>
??</si>
</iq>
復制代碼
A:
<iq id="x36vr-55" to="zhufu@domian/android" type="get" from="saonian@domian/android">
??<query xmlns="http://jabber.org/protocol/disco#info"></query>
</iq>
復制代碼
B:
<iq id="x36vr-55" to="saonian@domian/android" type="result" from="zhufu@domian/android">
??<query xmlns="http://jabber.org/protocol/disco#info">
? ? <identity category="client" name="Smack" type="pc"/>
? ? <feature var="http://www.xmpp.org/extensions/xep-0166.html#ns"/>
? ? <feature var="urn:xmpp:tmp:jingle"/>
??</query>
</iq>
復制代碼
A:
<iq id="x36vr-56" to="zhufu@domian/android" type="set" from="saonian@domian/android">
??<open xmlns="http://jabber.org/protocol/ibb" block-size="4096" sid="jsi_3326887048779603188" stanza="iq">
??</open>
</iq>
復制代碼
B:
<iq id="x36vr-55" to="saonian@domian/android" type="result" from="zhufu@domian/android">
??<query xmlns="http://jabber.org/protocol/disco#info">
? ? <identity category="client" name="Smack" type="pc"/>
? ? <feature var="http://jabber.org/protocol/xhtml-im"/>
? ? <feature var="http://jabber.org/protocol/muc"/>
? ? <feature var="http://jabber.org/protocol/bytestreams"/>
? ? <feature var="http://jabber.org/protocol/commands"/>
? ? <feature var="http://jabber.org/protocol/si/profile/file-transfer"/>
? ? <feature var="http://jabber.org/protocol/si"/>
? ? <feature var="http://jabber.org/protocol/ibb"/>
??</query>
</iq>
復制代碼
B:
<iq id="x36vr-56" to="saonian@domian/android" from="zhufu@domian/android" type="result"/>
復制代碼
A:
<iq id="x36vr-57" to="zhufu@domian/android" type="set" from="saonian@domian/android">
??<data xmlns="http://jabber.org/protocol/ibb" seq="0" sid="jsi_3326887048779603188">iVBORw0KGgoAAAANSUhEUgAAAEMAA
??</data>
</iq>
復制代碼
B:
<iq id="x36vr-57" to="saonian@domian/android" from="zhufu@domian/android" type="result"/>
復制代碼
A:
<iq id="x36vr-58" to="zhufu@domian/android" type="set" from="saonian@domian/android">
<data xmlns="http://jabber.org/protocol/ibb" seq="1" sid="jsi_3326887048779603188">dcwRxoSYEFYOgxc0Qx2TSCNDSJZRTxKFgVmZiKFN</data>
</iq>
復制代碼
B:
<iq id="x36vr-58" to="saonian@domian/android" from="zhufu@domian/android" type="result"/>
復制代碼
A:
<iq id="x36vr-59" to="zhufu@domian/android" type="set" from="saonian@domian/android">
<close xmlns="http://jabber.org/protocol/ibb" sid="jsi_3326887048779603188"/>
</iq>
復制代碼
B:
<iq id="x36vr-59" to="saonian@domian/android" from="zhufu@domian/android" type="result"/>
復制代碼
轉(zhuǎn)載于:https://my.oschina.net/vdroid/blog/202261
總結(jié)
以上是生活随笔為你收集整理的XMPP文件传输(XEP-0096协议说明)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【运动快乐】享受赤脚慢跑 收获健康快乐
- 下一篇: 网站分析