XMPP文件传输(XEP-0096协议说明)
XMPP XEP-0096協議是XMPP中的文件傳輸協議。
? ?? ? 關于文件傳輸,在xmpp協議中有不少協議可以實現,而XEP-0096協議是其中非常簡單的一個協議。由于郵件被刪,我的代碼demo丟失,因此只能在這里給大家講一下其中的邏輯實現,大家可以以此來寫出代碼。
? ?? ? 首先申明一下,以下是我個人對XEP-0096協議的一些認識和解釋,如有疑問,請發郵件到lizhanzhishang@gmail.com ,歡迎交流~
? ?? ? 我們根據openfire服務器做開發,但是服務器在這里只是起路由尋址和轉發的作用,實質上是完全點對點的通信,數據處理由客戶端來做。
? ?? ? 我們可以舉一個栗子,有兩部手機,互相之間使用message協議傳遞信息的完整message XML數據,可以看看一個客戶端發送的是什么信息,另一個客戶端接收的又是什么message信息,要是一樣,說明的是服務器是轉發的數據,要是不一樣的 話,則可能帶有IQ ,MSG,Pr信息。(但是總是有例外的,服務器也要對連接的數據做一些心跳包。)
? ?? ? 下面是一組請求(一方發出“發送文件”請求,接收方發出“拒絕接受”請求):
? ?? ? 這是”發送文件”的一段數據請求,(圖片小,可以雙擊放大)
? ?? ?將接受方拒絕接受文件的信息返回給發送方:
? ?? ?就此請求完畢,一方發出了“發送文件”的請求,另一方“拒絕”了這個請求。
? ?? ?這里有一個完整的數據傳輸協議,在官方的文檔上是這樣寫的:
? ?? ?上面的意思是說文件傳輸實際上是有協議XEP-0065和XEP-0047來進行的,而XEP-0096實際是傳輸IQ的消息協議,真正的傳輸數據并不 在次協議中,實現文件傳輸協議必須是full JID而且要求接收方在線。如果”to”(接收端), ”from”(發送端) 不是一個full JID,服務器就會發送error信息到”發送端”,說明服務器現在出現異常問題。
? ?? ?現在我們來說說在傳輸消息的時候,該怎么具體組織消息:
? ?? ?我們可以用IQ或者Message來發送數據。下面是我截取的文檔中我覺得相當重要的部分:
? ?? ?上面說啥呢,我英語也菜,但是能看懂一點2個關鍵點,一個是base64-encoding,block-size這個2個關鍵的單詞,說明我們在遇到 大文件的情況下是進行分塊發送的,每塊的數據都是一定字節的,例如,我們發送數據1024字節,但是那個流怎么發送呢,都是二進制的。我們直接發送呢,數 據太大,不好整的,再則直接轉String呢,那也是有問題的,因為String遇到’\o’就說明數據結束,會使數據漏掉很多。 文檔中告訴我們,將發送的文件轉換為base64之后再轉為String類型,放入IQ或者Message數據格式中發送。關于base64的理論資料在 這里:http://zh.wikipedia.org/zh-cn/Base64=
? ?? ?下面是一個數據實例:
? ?? ?參考的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數據不一定用IQ發送,還可以用Message發送。只是在參數上有個改變一下就可以,哈哈。
? ?? ?例子如下所示:
? ?? ?突然想起一件事情。。。在發送文件的時候,會有一個帶<si >標簽的數據段,這個數據段有id。這個id很重要,是必須要保存的。主要用在傳輸數據的時候,要是這個sid要是沒有帶上,那服務器就會返回錯誤信息給文件發送方。
? ?? ?還有個小事情,我當初解析命名空間的時候,以為是一般屬性,總是解析不出來。
最后發現有專門解析命名空間的東西,大家可以去google下。。。
? ?? ?下面是進行文件傳輸的XEP-0096協議的完整xml例子:
數據協議都是人定的,哈哈
文件發送方:
? ?? ?我們可以對此IQ數據段解析,當發現file 標簽的命名空間是http://jabber.org/protocol/si/profile/file-transfer的 時候 ,則表明這是“文件傳輸”消息請求。說明有人要傳文件了。對于這個xml請求,我們在提取數據的時候必須提取<si>標簽的ID。這個ID很 重要,是下面的sid傳輸數據的重要參數,也是判斷是否是同一個數據流的依據。還有就是提取mine-type標簽內容,這個是我們用來判斷接收的是何種 文件,并以此判斷創建該類型文件,把將要傳來的數據寫入這個文件,還有就是size標簽內容,來檢驗我們接收的文件是否完整。
下面是一個完整的沒有進行base64轉換的數據請求:
文件接收方:
? ?? ?這里說明,我要接受的數據是什么協議,主要在file var這個參數:stream-method
<x submit>這個表明我要接受數據,你可以發給我了。
發送文件方:
? ?? ?其實也要實現這個xml的,我不知道,當我接受數據之后,為什么要查詢對方的機器名字,和一些基本數據,這可能是進行確認。
? ?? ?接受方發出本機基本信息,主要有3個參數,category="client" name="Smack" type="pc"
? ?? ?查詢之后就開始要發數據了,哈哈。
? ?? ?發出數據肯定要打開流,發送數據結束也要關閉流的,哈哈
發送方發送打開消息:
? ?? ?這個xml雖然很少,但是每個數據都很重要呢。Open的命名空間很熟悉那。其實這個就是前面剛開始接受數據file里的value,block- size說的是,我每次傳數據都是以4096字節發送一個數據流。 這個sid就是發送方發送請求文件的那個<si>標簽的id。都是相同的,同時還有一個重要的東西,stanza="iq"這個,相當的重 要,這個標簽告訴對方,我要以IQ數據類型發送數據,這里也可以用message代替iq。前面我已經提及到。
下面的是message發送base64數據,如果stanza="message” 自己可以參照IQ發送base64數據。過程基本一樣,就是iq變成message而已:
接受方數據xml:
? ?? ? 上面的2個IQ是順序發送的,不可逆,第一個是主要告訴對方。同時,那3個參數是上上面的一樣的,要不是無法接收到額,還有一些對特征解釋,說明傳輸的可以哪些流、
然后緊接著告訴對方,我可以解釋數據了。
發送方開始發數據了,哈哈:
? ?? ?這個data的value,是前面的數據塊,4096字節base64加密數據。如果數據base64大于這個塊。我們接到這個數據首先要base64解密之后,再寫入剛才建立的文件中,
Sid是上面我們說的第一次si 標簽的id。不能改變,更不能為null。也不要不設置,不然服務器就會返回錯誤信息。 Seq是從0開始的,如果還有流就會依次遞增的,
如果接受處理完畢,就發送一個iq。說明接受完成??
說明一下哈,data里的數據被我刪掉N多,我這主要是說明用。
接受方:
? ?? ?發一個一個4096字節base64加密數據。這個是源文件base64加密偏移的數據。
? ?? ?上面的seq變成1了,而sid依然沒變。接受完成處理后,一樣要回復一下,告訴他,可以繼續傳數據了。
? ?? ?最后就是base64加密完成傳輸,要colse掉數據。
? ?? ?發送方關閉流,這個sid依舊沒有變,協議是這樣規定的:
? ?? ?好吧,我知道你關閉流了。我們之間的文件傳輸完成了:
寫了幾個小時分析,真的累。哎,下面貼出完整的流程xml
下面是整個對話階段的xml數據: A:發送方
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"/>
復制代碼
轉載于:https://my.oschina.net/vdroid/blog/202261
總結
以上是生活随笔為你收集整理的XMPP文件传输(XEP-0096协议说明)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【运动快乐】享受赤脚慢跑 收获健康快乐
- 下一篇: SQL Server 视图设计器