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

在网络不稳定时,openfire容易出现掉包情况,原因是在客户端掉线时,openfire并不能马上知道客户端已经断线,至于要多久才能发现客户端断线,跟服务器端设置的Idle Connections 时间有关。默认为360秒。 为解决掉包问题,xmpp协议支持消息回执,这个只需在客户端发消息时设置要求回执就行,服务器端不需要另外设置。

使用smack设置消息回执方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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

openfire smack消息回执设置,处理掉包问题_第1张图片


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

openfire smack消息回执设置,处理掉包问题_第2张图片

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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="[email protected]" from="[email protected]/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="[email protected]/pc" from="[email protected]"><received xmlns="urn:xmpp:receipts" id="e3539-31"/></message>



你可能感兴趣的:(openfire)