asmack实现端到端的消息回执(XEP-0184: Message Delivery Receipts)

要想保证信息的传输,目前在smack/asmack + openfire架构上,我个人想到有两种实现方式:


1.端到端确保发送(类似短信)。

其实这个就是xmpp协议的XEP-0184: Message Delivery Receipts.

里边为了确保消息的到达,需要接收方返回回执,这样发送方就知道对方是否确切收到消息。

当然咯,接收回执过程中也可能出现断线,导致发送方收不到回执,而认为接收方没收到,再重新发的问题,这个需要接收方过滤掉重复的信息来解决。

其实这个协议,asmack在0.8.3版本就已经支持,具体什么版本开始,就懒得去研究了。

需要注意的是:这个是两个客户端之间的事情,即openfire什么也不用干,只要客户端都支持xep-0184就可以了。

 

下面简单说下xep-0184协议的交互内容:

发送方发送一个需要回执的消息:

<message from='[email protected]/westminster'
 					id='richard2-4.1.247'
					to='[email protected]/throne'>
	<body>My lord, dispatch; read o'er these articles.</body>
	<request xmlns='urn:xmpp:receipts'/>
</message>

 

接收方收到消息后,返回的消息:

<message from='[email protected]/throne'
 				id='bi29sg183b4v'
  			to='[email protected]/westminster'>
    <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>
</message>


注意回执的id要与接收的packetID对应。

 

好了,了解原理了。大家来看看asmack是怎么实现的。

http://bamboo.igniterealtime.org/browse/SMACK-TRUNK-59/commit 上说的好简单,实际上你不会成功的,因为asmack有bug抓狂,目前最新的0.8.5上也没解决。

下面跟大家介绍怎么使用消息回执及解决这个bug。奋斗

 

发送需要回执的消息前,调用

DeliveryReceiptManager.addDeliveryReceiptRequest(packet);
myConnection.sendPacket(packet);

来为你的packet添加<request xmlns='urn:xmpp:receipts'/>节点。

 

在初始化xmppconnection后,调用

DeliveryReceiptManager.getInstanceFor(myConnection)
             .enableAutoReceipts();

来设置自动进行回执,设置后,回执的事情就不用我们自己操心啦。

好了,要做的事情就这么点。额,尴尬,,本来应该就这么点。但是。。asmack有bug啊发火,他把request跟received都用同一个ExtensionProvider啦!!

证据在org.jivesoftware.smackx.ConfigureProviderManager类里边这两句:

	// XEP-184 Message Delivery Receipts
	pm.addExtensionProvider("received", "urn:xmpp:receipts", new DeliveryReceipt.Provider());
	pm.addExtensionProvider("request", "urn:xmpp:receipts", new DeliveryReceipt.Provider());

都用了同一个Provider,当然出问题了。就是接受者无法找到<request xmlns='urn:xmpp:receipts'/>节点,因为DeliveryReceipt.Provider()生成的是received节点。

于是乎,自动回执没有效果。

“改吧!。。”

“不改jar包行不行啊?”

“行啊!”

如下:

            sAndroid = SmackAndroid.init(cxtContext);
            ProviderManager pm = ProviderManager.getInstance();
            // add delivery receipts
            pm.addExtensionProvider(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE,
                    new DeliveryReceipt.Provider());
            pm.addExtensionProvider(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE,
                    new DeliveryReceiptRequest.Provider());


将jar包中错误的设置,重新设置一下。这样,消息回执功能就大功告成啦。。

xep-0184里边还讲了如何判断客户端是否支持消息回执的问题,如果你有这样的需求,就自己去了解吧。


2.openfire服务端确保消息发送到达(待续)

我不知是否是由于MINA太旧的原因,导致openfire在nio发送的过程中,无法捕获发送异常,导致无法识别异常断线的客户端,也就不能准确的保存离线消息。
openfire目前用的MINA是1.1.7版本,可能是这个版本有问题。apache在这版本上进行了重大的调整和改造,版本号直接改成2.0.0。因此直接升级openfire的MINA包难度很大,连openfire开发者们都拖了这么些年不更新MINA版本。。

这个原因纯属个人猜测,于是这个方法走不通。有兴趣的同学可以试试,熟悉MINA的人应该能看出来。

 

既然底层机制不可变,那就只能通过自己的手法来处理了。


这个我目前在实践中,或许下一篇就会讲到。

你可能感兴趣的:(openfire,XMPP)