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

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

  1. <message from='northumberland@shakespeare.lit/westminster'  
  2.                     id='richard2-4.1.247'  
  3.                     to='kingrichard@royalty.england.lit/throne'>  
  4.     <body>My lord, dispatch; read o'er these articles.</body>  
  5.     <request xmlns='urn:xmpp:receipts'/>  
  6. </message>  
<message from='northumberland@shakespeare.lit/westminster'
 					id='richard2-4.1.247'
					to='kingrichard@royalty.england.lit/throne'>
	<body>My lord, dispatch; read o'er these articles.</body>
	<request xmlns='urn:xmpp:receipts'/>
</message>

 

 

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

  1. <message from='kingrichard@royalty.england.lit/throne'  
  2.                 id='bi29sg183b4v'  
  3.             to='northumberland@shakespeare.lit/westminster'>  
  4.     <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/>  
  5. </message>  
<message from='kingrichard@royalty.england.lit/throne'
 				id='bi29sg183b4v'
  			to='northumberland@shakespeare.lit/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。奋斗

 

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

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

 

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

 

在初始化xmppconnection后,调用

  1. DeliveryReceiptManager.getInstanceFor(myConnection)  
  2.              .enableAutoReceipts();  
DeliveryReceiptManager.getInstanceFor(myConnection)
             .enableAutoReceipts();

 

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

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

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

  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());  
	// XEP-184 Message Delivery Receipts
	pm.addExtensionProvider("received", "urn:xmpp:receipts", new DeliveryReceipt.Provider());
	pm.addExtensionProvider("request", "urn:xmpp:receipts", new DeliveryReceipt.Provider());

(注:目前asmack.jar的新版本0.8.9已经修改了此处的bug---2013-11-19)

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

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

“改吧!。。”

“不改jar包行不行啊?”

“行啊!”

如下:

  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());  
            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的人应该能看出来。

 

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

 

转自:http://blog.csdn.net/t8500071/article/details/13094933

可参考:http://www.oschina.net/question/699232_105798

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值