openfire smack消息回执设置,处理掉包问题

在网络不稳定时,openfire容易出现掉包情况,原因是在客户端掉线时,openfire并不能马上知道客户端已经断线,至于要多久才能发现客户端断线,跟服务器端设置的Idle Connections 时间有关。默认为360秒。

为解决掉包问题,xmpp协议支持消息回执,这个只需在客户端发消息时设置要求回执就行,服务器端不需要另外设置。

使用smack设置消息回执方法

package com.penngo.test;

import java.awt.EventQueue;

public class ReceiptDialog extends JDialog {
	private JTextField textField;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ReceiptDialog dialog = new ReceiptDialog();
					dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
					dialog.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the dialog.
	 */
	public ReceiptDialog() throws Exception{
		setBounds(100, 100, 450, 300);
		getContentPane().setLayout(null);
		
		textField = new JTextField();
		textField.setBounds(20, 20, 301, 22);
		getContentPane().add(textField);
		textField.setColumns(10);
		
		Connection.DEBUG_ENABLED = true;  // 打开smack debug

		
		ConnectionConfiguration config = new ConnectionConfiguration("127.0.0.1", 5222);//52222
		config.setSendPresence(true);
		final Connection connection = new XMPPConnection(config);
		
		// 自动回复回执方法,如果对方的消息要求回执。
		ProviderManager pm = ProviderManager.getInstance();
		pm.addExtensionProvider(DeliveryReceipt.ELEMENT, DeliveryReceipt.NAMESPACE, new DeliveryReceipt.Provider()); 
		pm.addExtensionProvider(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE, new DeliveryReceiptRequest.Provider());
		DeliveryReceiptManager.getInstanceFor(connection).enableAutoReceipts();
		
//		非自动回复回执方法
//		connection.addPacketListener(new PacketListener() {
//			public void processPacket(Packet packet) {
//				// 监听消息,在检查到对方要求回执时,客户端手动发送回执给对方
//				if(packet instanceof Message){
//					Message message = (Message)packet;
//					PacketExtension receipt = message.getExtension(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
//					if(receipt != null){
//						Message receiptMessage = new Message();
//						receiptMessage.setTo(message.getFrom());
//						receiptMessage.setFrom(message.getTo());
//						receiptMessage.addExtension(new DeliveryReceipt(message.getPacketID()));
//						connection.sendPacket(receiptMessage);
//					}
//				}
//			}
//		}, new PacketFilter() {
//			public boolean accept(Packet packet) {
//				return true;
//			}
//		});
		
		connection.connect();
		String domain = connection.getServiceName();

		// test1登录,发送消息给test2
//		String from = "test1";
//		final String to = "test2" + "@" + domain;
		
		//test2登录,发送消息给test1
		String from = "test2";
		final String to = "test1" + "@" + domain;
		
		connection.login(from, "123456", "pc");
//		Presence p = new Presence(Presence.Type.available);
//		p.setMode(Mode.chat);
//		p.setStatus("在线");
//		connection.sendPacket(p);

		final Chat chat = connection.getChatManager().createChat(to, null);
		
		JButton sendButton = new JButton("发送");
		sendButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Message message = new Message();
				message.setFrom(connection.getUser());
				message.setTo(to);
				message.setBody(textField.getText());
				
				// 添加回执请求
				DeliveryReceiptManager.addDeliveryReceiptRequest(message);  
				
				//也可以这样添加回执请求
				//DeliveryReceiptRequest deliveryReceiptRequest = new DeliveryReceiptRequest();
                                //message.addExtension(new DeliveryReceiptRequest());
				
				System.out.println("发送=======" + message.toXML());
				try{
					chat.sendMessage(message);
				}
				catch(Exception ex){
					ex.printStackTrace();
				}
				
				
			}
		});
		sendButton.setBounds(331, 19, 93, 23);
		getContentPane().add(sendButton);

	}
}

运行结果,在smack debug window中查看数据

test2发送消息给test1,消息id为Winlh-55

000319_INbV_117179.jpg


test1发送回执给test2,告诉test2消息Winlh-55已经收到

000319_kr1r_117179.jpg

上边的方法只是客户端对客户端的消息回执,另外也可以在服务器端发送回执给客户端,告诉客户端已经收到消息

package com.penngo.openfire;
import java.io.File;
import org.dom4j.Element;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.container.Plugin;
import org.jivesoftware.openfire.container.PluginManager;
import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.xmpp.packet.Message;
import org.xmpp.packet.Packet;

public class ReceiptPlugin implements Plugin, PacketInterceptor{
    private XMPPServer server;
    private String domain;
    private InterceptorManager interceptorManager;

    public void initializePlugin(PluginManager manager, File pluginDirectory) {
        server = XMPPServer.getInstance();
        domain = XMPPServer.getInstance().getServerInfo().getXMPPDomain();
        interceptorManager = InterceptorManager.getInstance();
        interceptorManager.addInterceptor(this);
    }

	public void interceptPacket(Packet packet, Session session,
			boolean incoming, boolean processed) throws PacketRejectedException {
		if(packet instanceof Message && incoming == true && processed == false){
			Message message = (Message)packet;
			String to = message.getTo().getNode();
			//注意插件中Message类来自tinder.jar包, DeliveryReceipt来自smackx.jar包
//			PacketExtension receipt = message.getExtension(DeliveryReceiptRequest.ELEMENT, DeliveryReceipt.NAMESPACE);
			Element receipt = message.getChildElement("request", "urn:xmpp:receipts");
			if(receipt != null){
				Message receiptMessage = new Message();
				receiptMessage.setTo(message.getFrom());
				receiptMessage.setFrom(message.getTo());
//				Element received = receiptMessage.addChildElement(DeliveryReceipt.ELEMEN, DeliveryReceipt.NAMESPACE);
				Element received = receiptMessage.addChildElement("received", "urn:xmpp:receipts");
				received.setAttributeValue("id", message.getID());
				try{
					server.getPacketDeliverer().deliver(receiptMessage);
				}
				catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	}
	
    public void destroyPlugin() {
        interceptorManager.removeInterceptor(this);
    }
}

xmpp消息回执协议:

发送者message加上<request xmlns='urn:xmpp:receipts'/>要求接收者发送回执

<message id="e3539-31" to="test1@xxx.com" from="test2@xxx.com/pc" type="chat"><body></body><thread></thread><request xmlns='urn:xmpp:receipts'/></message>


接收者在收到消息后回复一条message,并把消息的id放到<received xmlns="urn:xmpp:receipts" id="e3539-31"/>,告诉发送者已经收到

<message to="test2@xxx.com/pc" from="test1@xxx.com"><received xmlns="urn:xmpp:receipts" id="e3539-31"/></message>


开发者在使用时,也可以根据业务需要定义自己的回执格式。


转载于:https://my.oschina.net/penngo/blog/339064

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值