如何在Android上保持XMPP连接稳定(a)smack?

我使用Android的asmackandroid-7-beem库。 我有一个后台服务正在运行,例如我的应用程序保持活动状态。 但是,XMPP连接迟早会在没有任何通知的情况下死亡。 服务器说客户端仍然在线,但没有发送或接收数据包。

例如,当其他客户端具有新的存在时,客户端不接收任何存在分组。 我有XMPPConnection作为我的主要Application类的一个属性。
我在建立ConnectionConfiguration config.setReconnectionAllowed(true)之前设置了ConnectionConfiguration config.setReconnectionAllowed(true)
但重新连接不会发生。 XMPPConnection connection.isConnected()返回true。

因此客户端不知道连接实际上已丢失。

有没有办法保持连接活着?

Solutions Collecting From Web of "如何在Android上保持XMPP连接稳定(a)smack?"

当使用asmack时,在你的应用程序中添加这样的代码,使Dalvik加载ReconnectionManager类并运行它的静态初始化块:

 static { try { Class.forName("org.jivesoftware.smack.ReconnectionManager"); } catch (ClassNotFoundException ex) { // problem loading reconnection manager } } 

实际上重新连接管理器没有任何问题。 首先,您需要将连接侦听器添加到连接管理器。

 connection.addConnectionListener(new ConnectionListener() { @Override public void reconnectionSuccessful() { Log.i("","Successfully reconnected to the XMPP server."); } @Override public void reconnectionFailed(Exception arg0) { Log.i("","Failed to reconnect to the XMPP server."); } @Override public void reconnectingIn(int seconds) { Log.i("","Reconnecting in " + seconds + " seconds."); } @Override public void connectionClosedOnError(Exception arg0) { Log.i("","Connection to XMPP server was lost."); } @Override public void connectionClosed() { Log.i("","XMPP connection was closed."); } }); 

如果发生任何错误,则在关闭连接时将自动调用connectionClosedOnError(Exception arg0)

  public void connectionClosed() { Log.i("","XMPP connection was closed."); //You can manually call reconnection code if you want to reconnect on any connection close } 

然后检查它会调用reconnectingin()方法并尝试重新连接。

希望这对你有所帮助。

使用下面的代码进行检查连接PingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(5000); PingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(5000);

添加用于ping失败处理的列表器以处理连接是否已连接,因为isConnected方法对于检查连接状态是不可靠的。

pingManager.registerPingFailedListener(PingFailedListener);

对于移动网络连接是一个非常大的问题,因此您需要使用广播接收器检查移动设备的网络连接,并且在数据重新连接时您可以使用pingMyServer方法检查连接是否存活,如果您从服务器获得ping回复,则表示连接处于活动状态否则在ping失败时,您可以手动重新连接连接。

我有同样的问题,除了我的程序在服务器端JVM上运行。
我首先使用了smack 4.0。 然后我更新了1.4,但问题仍然发生。 最后我find了一个配置模块: PingManager
使用它之后,这种情况的发生就下降了。

  connection = new XMPPTCPConnection(config); PingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(300); // seconds 

这是我的代码适用于ReconnectionManager

1)在xmpp连接上添加addConnectionListener

 XMPPConnectionListener mConnectionListener = new XMPPConnectionListener(username); connection.addConnectionListener(mConnectionListener); 

2)如果连接关闭,则使用ReconnectionManager类自动ReconnectionManager

  ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection); reconnectionManager.enableAutomaticReconnection(); reconnectionManager.setEnabledPerDefault(true); 

3) ConnectionListener用于在服务器上重新连接,连接和validation。 如果连接已成功通过服务器validation,则还会注册PingManagerServerPingWithAlarmManager类。

 public class XMPPConnectionListener implements ConnectionListener { String username=""; public XMPPConnectionListener(String username){ this.username=username; } @Override public void connected(final XMPPConnection connectionObeject) { sendPresenceAvailable(); Log.d(TAG, "xmpp Connected()"); connected = true; } @Override public void connectionClosed() { Log.d(TAG, "xmpp ConnectionCLosed()"); isAuthenticatedPreviouly=false; connected = false; loggedin = false; } @Override public void connectionClosedOnError(Exception arg0) { Log.d(TAG, "xmpp ConnectionClosedOnError() :"+System.currentTimeMillis()); isAuthenticatedPreviouly=false; connected = false; loggedin = false; } @Override public void reconnectingIn(int arg0) { Log.d(TAG, "xmpp reconnectingIn() :"+System.currentTimeMillis()); loggedin = false; } @Override public void reconnectionFailed(Exception arg0) { Log.d(TAG, "xmpp ReconnectionFailed!"); connected = false; // chat_created = false; loggedin = false; try { connection.connect(); } catch (SmackException | IOException | XMPPException | InterruptedException exception) { exception.printStackTrace(); } } @Override public void reconnectionSuccessful() { Log.d(TAG, "xmpp ReconnectionSuccessful"); connected = true; sendPresenceAvailable(); loggedin = false; } @Override public void authenticated(XMPPConnection connection2, boolean resumed) { Log.d(TAG, "xmpp Type Main Authenticated() :" + connection.isAuthenticated()); if(connection.isAuthenticated()) { ServerPingWithAlarmManager.getInstanceFor(connection).setEnabled(true); PingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(10); try { pingManager.pingMyServer(); pingManager.pingMyServer(true,10); pingManager.pingServerIfNecessary(); pingManager.registerPingFailedListener(new PingFailedListener() { @Override public void pingFailed() { Log.d("Ping","pingFailed"); disconnect(); connect(); } }); registerAllListener(); } } 

在Smack 4.1中,我使用ServerPingWithAlarmManager 。 你可以在这里find关于保持连接ramzandroid博客的更多细节。

对于这些情况,您需要手动处理断开连接我的意思是您应该拦截任何断开连接,当断开连接时通知连接侦听器。

public void connectionClosedOnError(exceptionexception)

  import android.util.Log; import com.dagm8.core.protocols.ConnectionState; import com.dagm8.core.service.XMPPService; import com.dagm8.events.ConnectionStateEvent; import org.greenrobot.eventbus.EventBus; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import java.io.IOException; import static com.dagm8.core.protocols.ConnectionState.CONNECTED; import static com.dagm8.core.protocols.ConnectionState.DISCONNECTED; import static com.dagm8.core.protocols.ConnectionState.RECONNECTING; /** * dagm8-android * Created by Bedoy on 8/28/17. */ public class ConnectionController implements ConnectionListener { private String TAG = getClass().getCanonicalName(); private XMPPTCPConnection mConnection; public void setConnection(XMPPTCPConnection connection) { mConnection = connection; } public void init(XMPPTCPConnection connection) throws InterruptedException, XMPPException, SmackException, IOException { setConnection(connection); mConnection.setPacketReplyTimeout(10000); mConnection.addConnectionListener(this); mConnection.connect(); } @Override public void connected(XMPPConnection connection) { XMPPService.connectionState = RECONNECTING; notifyConnectionState(RECONNECTING); try { mConnection.login(); } catch (XMPPException | SmackException | IOException | InterruptedException e) { e.printStackTrace(); } Log.i(TAG, "connected()"); } @Override public void authenticated(XMPPConnection connection, boolean resumed) { XMPPService.connectionState = CONNECTED; notifyConnectionState(CONNECTED); Log.i(TAG, "authenticated()"); } @Override public void connectionClosed() { XMPPService.connectionState = DISCONNECTED; notifyConnectionState(DISCONNECTED); Log.i(TAG, "connectionClosed()"); } @Override public void connectionClosedOnError(Exception e) { XMPPService.connectionState = DISCONNECTED; notifyConnectionState(DISCONNECTED); try { mConnection.connect(); } catch (SmackException | IOException | XMPPException | InterruptedException exception) { exception.printStackTrace(); } Log.i(TAG, "connectionClosedOnError()"); } @Override public void reconnectingIn(int seconds) { XMPPService.connectionState = RECONNECTING; notifyConnectionState(RECONNECTING); Log.i(TAG, "reconnectingIn()"); } @Override public void reconnectionSuccessful() { XMPPService.connectionState = CONNECTED; notifyConnectionState(CONNECTED); Log.i(TAG, "reconnectionSuccessful()"); } @Override public void reconnectionFailed(Exception e) { XMPPService.connectionState = DISCONNECTED; notifyConnectionState(DISCONNECTED); Log.i(TAG, "reconnectionFailed()"); } private void notifyConnectionState(ConnectionState state) { EventBus.getDefault().post((ConnectionStateEvent) () -> state); } public boolean isAuthenticated() { return mConnection.isAuthenticated(); } public void login() { try { mConnection.login(); } catch (XMPPException | SmackException | IOException | InterruptedException e) { e.printStackTrace(); } } }