iOS客户端 Openfire服务 利用XEP-0065和XEP-0096 做out-of-band bytestream文件传输
Openfire服务可以做文件传输方法可供选择有:
- XEP-0047: in-band bytestreams:带内字节流传输协议 base64编码后放入iq消息,同普通文字消息,编解码需耗点资源效率一般,适用于较小文件;
- XEP-0096: SI File Transfer:文件传输流初始化协议
- 文档中提到可自行选择开发支持断点续传。当file元素包含range无素时,range包含offset、length两个属性,可以指出要传送的数据位于文件的什么位置。
- XEP-0065: SOCKS5 Bytestreams:带外socks5代理字节流传输协议
- 文档中提到 如果发送端位于公网,则接收端直接连接发送端拉取数据。如果双方都位于内网,则双方连接代理服务器,通过代理服务器转发数据。
- 两种应用场景原文:
- A direct connection in which the StreamHost is the Requester, as described under Direct Connection
- A mediated connection in which the StreamHost is a Proxy, as described under Mediated Connection
- XEP-0066: Out of Band Data:带外数据传输协议
- 具体看协议文档,没搞过;XEP-0096中提到XEP-0066的drawbacks,原文:
-
- It is not reliable.
- It does not work when one of the parties is behind a firewall.
- It provides limited metadata about files to be exchanged
- 还有一种,自建个文件服务器,发送方发送文件到文件服务器,上传成功后生成相应的缩略图(如果是图片文件的话)推送完成的消息给接收方,接收方收到消息后,去下载相应的文件,比较好理解,但我猜想每次比上述的方式多了次 磁盘IO;项目进度急得话,也是可以选用,可后续优化嘛。
我选的是XEP-0096和XEP-0065 :
XEP-0096对应的iOS版本文件 地址,XEP-0065 iOS 版本也可用上述地址的版本
初始化XMPPStream时需要注意:
1
2
3
|
XMPPJID *jid = [XMPPJID jidWithString:[
NSString
stringWithFormat:@
"%@@%@"
, account, XMPPDomain]];
XMPPJID *jidWithResource = [jid jidWithNewResource:@
"ios"
];
[
self
.xmppStream setMyJID:jidWithResource];
|
普通JID格式如:account@domain (形如 hanmeimei@test)
第二行带上resource,不带我的程序报错:
<error code="503" type="cancel"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
应该是两端的resource不一致
初始化XMPPSIFileTransfer相应代码:
1
2
3
4
5
|
NSString
*sessionId = [_xmppStream generateUUID];
_sifiletransfer = [[XMPPSIFileTransfer alloc] init];
_sifiletransfer.sid = sessionId;
[_sifiletransfer addDelegate:
self
delegateQueue:dispatch_get_main_queue()];
[_sifiletransfer activate:_xmppStream];
|
发送文件:
1
2
3
4
|
- (
void
)sendImageMessage:(
NSData
*)imageData toAccount:(
NSString
*)account{
XMPPJID *jid = [XMPPJID jidWithString:[
NSString
stringWithFormat:@
"%@@%@/%@"
, account, XMPPDomain, [[_xmppStream myJID] resource]]];
[_sifiletransfer initiateFileTransferTo:jid withData:imageData];
}
|
其中文件接收方的JID完整格式:account@domain/resource (形如 hanmeimei@test/ios)
发送完成后在XMPPSIFileTransfer.h中的
1
2
3
4
|
@protocol
XMPPSIFileTransferDelegate <
NSObject
>
@required
- (
void
)receivedImage:(
NSData
*)image from:(XMPPJID*)from;
@end
|
可在你自己的文件中实现该方法接受文件
至此,我在内网可以通过此方式传输文件,Mac下得openfire服务,可选用源码或dmg方式 均可;
后来测试一端内网,一端外网出现错误,提示为:
<error code="404" type="cancel"><item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error>
openfire后台配置:
注意xmpp.proxy.externalip 填写你测试服务器的外网地址
路由器的7777端口也要映射到外网,如图:
至此,内外网两端发送文件测试也通过。