【问题标题】:How to keep a XMPP connection stable on Android with (a)smack?如何使用 (a) smack 在 Android 上保持 XMPP 连接稳定?
【发布时间】:2012-10-16 08:12:16
【问题描述】:

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

例如,当其他客户端有新的状态时,客户端不会收到任何状态数据包。我将 XMPPConnection 作为我的主要应用程序类的属性。
我在建立连接之前设置了ConnectionConfiguration config.setReconnectionAllowed(true)
但重新连接不会发生。 XMPPConnection connection.isConnected() 返回真。

所以客户端并不知道连接实际上已经丢失。

有什么方法可以保持连接吗?

【问题讨论】:

  • isConnected 方法返回对象状态,但 smack 无法处理网络连接更改您需要编写代码检查您是否能够 ping 服务器,基于您需要执行进一步操作,了解更多详细信息你可以看到查看我的答案

标签: android connection xmpp smack


【解决方案1】:

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

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

【讨论】:

  • 对此有何解释?
  • @ingyesid 这是在 ReconnectionManager 类中执行静态初始化块所必需的,它实际上激活了它。但是我会仔细检查,因为无论如何它都应该由 asmack 静态初始化程序初始化(如果你使用它)。
  • 嗨@Martin Konecny。我一直在尝试创建 XMPPConnection 但连接失败。不过,XMPPServer 可以正常启动。你能看看我的问题here,看看你能不能帮忙?提前谢谢你。
  • 在 Android 上使用 ReconnectionManager 通常不是完整的解决方案,因为您希望在数据连接发生变化时做出反应(例如 GSM 到 Wifi 切换),而 ReconnectionManager 不知道例如Android 的 NETWORK_CONNECTIVITY_CHANGED 意图。同样在 Android 上运行的较新的 Smack 版本(4.1 或更高版本)上,不再需要手动进行初始化:Smack 将自动完全初始化。
【解决方案2】:

其实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);

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

pingManager.registerPingFailedListener(PingFailedListener);

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

【讨论】:

  • 嗨 Mandeep,我完全按照你的回答说它仍然不起作用。连接大约只存在 5 分钟。我虽然我错过了一些东西。这是我的代码:link MainActivity.java 你能看看这个并告诉我我是否像你一样吗?谢谢dropbox.com/s/ze3vjy08m2mymir/MainActivity.java?dl=0我在Android API 16和aSmack上:asmack-android-19-0.8.10.jar
  • 我也遇到了同样的问题,使用同一个.jar,你有没有搞清楚为什么一段时间后连接丢失了?
  • 嗨@Silvia.H。我一直在尝试创建 XMPPConnection 但连接失败。不过,XMPPServer 可以正常启动。你能看看我的问题here,看看你能不能帮忙?提前谢谢你。
【解决方案3】:

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

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

【讨论】:

  • 嗨@crazytomcat,如果你正在为android编写代码,你需要处理网络连接,并在你必须编写重新连接机制的地方添加处理pingfailedlistener的代码。
  • 当应用程序在后台时,我们如何才能阻止这种情况?
【解决方案4】:

在 Smack 4.1 中,我使用 ServerPingWithAlarmManager。你可以找到更多关于保持连接的细节ramzandroid blog here

【讨论】:

  • 我无法解决这个类。我正在使用compile 'org.igniterealtime.smack:smack-extensions:4.2.0'compile 'org.igniterealtime.smack:smack-android:4.2.0'
  • @joao2fast4u:我认为它会在 smack-android-extensions 上,基于此 github 链接:github.com/igniterealtime/Smack/blob/master/…
【解决方案5】:

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

public void connectionClosedOnError(异常异常)

    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();
            }
        }
    }

【讨论】:

    【解决方案6】:

    这是我的代码适用于 ReconnectionManager

    1) 在 xmpp 连接上添加addConnectionListener

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

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

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

    3) ConnectionListener 用于在服务器上重新连接、连接和验证。如果与服务器的连接验证成功,还注册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();
         }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-07
      • 2015-05-24
      • 1970-01-01
      • 2017-06-08
      • 2011-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多