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协议的交互内容:

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

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

 

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

[plain] view plaincopy
  1. <message from='[email protected]/throne'  
  2.                 id='bi29sg183b4v'  
  3.             to='[email protected]/westminster'>  
  4.     <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>  
  5. </message>  


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

 

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

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

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

 

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

[java] view plaincopy
  1. DeliveryReceiptManager.addDeliveryReceiptRequest(packet);  
  2. myConnection.sendPacket(packet);  

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

 

在初始化xmppconnection后,调用

[java] view plaincopy
  1. DeliveryReceiptManager.getInstanceFor(myConnection)  
  2.              .enableAutoReceipts();  

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

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

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

[java] view plaincopy
  1. // XEP-184 Message Delivery Receipts  
  2. pm.addExtensionProvider("received""urn:xmpp:receipts"new DeliveryReceipt.Provider());  
  3. pm.addExtensionProvider("request""urn:xmpp:receipts"new DeliveryReceipt.Provider());  

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

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

“改吧!。。”

“不改jar包行不行啊?”

“行啊!”

如下:

[java] view plaincopy
  1. sAndroid = SmackAndroid.init(cxtContext);  
  2. ProviderManager pm = ProviderManager.getInstance();  
  3. // add delivery receipts  
  4. pm.addExtensionProvider(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE,  
  5.         new DeliveryReceipt.Provider());  
  6. pm.addExtensionProvider(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE,  
  7.         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的人应该能看出来。

 

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章