有点奇怪,但我在监控XMPP连接的连接状态时遇到问题。我正在使用Smack(3.4.1)和Openfire(3.8.2)
Openfire报告客户端已断开连接。和我的远程客户端BOT一样,它负责中间人服务器请求。然而,设备本身仍然认为它们是连接的。所以有些东西突然扼杀了这种联系。
我可以通过Openfire管理控制台手动关闭客户端连接来复制方案。执行此操作后,客户端仍会报告已连接,并提供以下详细信息:
04-15 09:48:23.349: D/BXC(18166): Checking Xmpp connection status
04-15 09:48:23.349: I/BXC(18166): Xmpp Connection still valid
04-15 09:48:23.349: D/BXC(18166): isNull=false
04-15 09:48:23.349: D/BXC(18166): isConnected()=true
04-15 09:48:23.349: D/BXC(18166): isAuthenticated()=true
04-15 09:48:23.349: D/BXC(18166): xmppConnectorRunning=true
04-15 09:48:23.349: D/BXC(18166): socketIsClosed()=false
04-15 09:48:23.349: D/BXC(18166): Are we logged in?
04-15 09:48:23.349: I/BXC(18166): Yes - Logged in.
来自代码:
Log.d("BXC", "isNull=" + (xConnection == null));
Log.d("BXC", "isConnected()=" + xConnection.isConnected());
Log.d("BXC", "isAuthenticated()=" + xConnection.isAuthenticated());
Log.d("BXC", "xmppConnectorRunning=" + Globals.backgroundXmppConnectorRunning);
Log.d("BXC", "socketIsClosed()=" + xConnection.isSocketClosed());
问题是,在重新启动应用程序之前,连接将保持此状态。用于检查XMPP连接的实际状态的最佳值/数据/变量/方法调用是什么?
这是我的BackgroundXmppConnector服务代码(我很可能在此过程中发现了一些东西,但我看不到它):
package com.goosesys.gaggle.services;
import java.util.Collection;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.Roster.SubscriptionMode;
import org.jivesoftware.smack.RosterListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import com.google.gson.Gson;
import com.goosesys.gaggle.Globals;
import com.goosesys.gaggle.application.AppSettings;
import com.goosesys.gaggle.application.Utility;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class BackgroundXmppConnector extends Service
{
private ConnectionConfiguration acc;
private XMPPConnection xConnection;
private final IBinder mBinder = new XmppBinder();
private final Handler mHandler = new Handler();
private static int mInterval = (1 * 60 * 1000);
private static boolean bConnecting = false;
private static final Object connectLock = new Object();
private final Runnable checkConnection = new Runnable()
{
@Override
public void run()
{
checkConnectionStatus();
}
};
@Override
public void onCreate()
{
Log.i("BXC", "BackgroundXmppConnector Service has been created");
// Checks the connection state every 1 minute //
mHandler.postDelayed(checkConnection, mInterval);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
// SmackAndroid.init(getApplicationContext());
Log.d("BXC", "Xmpp Connector Started");
if(xConnection == null)
{
checkConnectionStatus();
}
return Service.START_STICKY;
}
private void setupConnection()
{
try
{
acc = new ConnectionConfiguration(AppSettings.XMPP_SERVER_HOST,
AppSettings.XMPP_SERVER_PORT);
acc.setSecurityMode(SecurityMode.disabled);
acc.setSASLAuthenticationEnabled(false);
acc.setReconnectionAllowed(true);
xConnection = new XMPPConnection(acc);
xConnection.addConnectionListener(new ConnectionListener()
{
@Override
public void connectionClosed()
{
Log.e("BXC", "Xmpp connection closed");
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}
@Override
public void connectionClosedOnError(Exception e)
{
Log.e("BXC", "Xmpp connection closed with error: " + e);
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}
@Override
public void reconnectingIn(int seconds)
{
Log.i("BXC", "Xmpp connection, reconnecting in " + seconds + " seconds");
bConnecting = true;
}
@Override
public void reconnectionFailed(Exception e)
{
Log.e("BXC", "Xmpp reconnection failed: " + e);
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}
@Override
public void reconnectionSuccessful()
{
Log.i("BXC", "Xmpp reconnected successfully");
Globals.backgroundXmppConnectorRunning = true;
bConnecting = false;
}
});
}
catch (Exception e)
{
Log.e("BXC", e.getMessage());
}
finally
{
// Schedule another check in 1 minute //
mHandler.postDelayed(checkConnection, mInterval);
}
if(xConnection.isAuthenticated() == false)
new LoginTask().execute();
}
public boolean sendMessage(Intent intent)
{
if(xConnection != null && xConnection.isConnected())
{
String jsonObject;
Bundle extras = intent.getExtras();
if(extras != null)
{
jsonObject = extras.getString("MESSAGEDATA");
Message m = new Gson().fromJson(jsonObject, Message.class);
if(m != null)
{
sendMessage(m);
}
else
{
Log.e("BXC", "Message to send was/is null. Can't send.");
}
m = null;
jsonObject = null;
extras = null;
}
Log.i("BXC", "Sending Xmpp Packet");
return true;
}
return false;
}
/*
* Sends message to xmpp server - message packet in form of
*
* --------------------MESSAGE PACKET-------------------------
* TO
* -----------------------
* FROM
* -----------------------
* BODY
* TRANSACTION-------------------------------------------
* MessageType
* --------------------------------------------------
* TransactionObject
*/
private void sendMessage(Message m)
{
try
{
Log.d("BXC", "Sending transaction message to Xmpp Server");
xConnection.sendPacket(m);
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public boolean isConnected()
{
return xConnection.isConnected();
}
private void checkConnectionStatus()
{
Log.d("BXC", "Checking Xmpp connection status");
if(!bConnecting)
{
// if connection object is null - re-create
if(xConnection == null) // || xConnection.isConnected() == false
{
// The connection has stalled for some reason - attempt a reconnect
Log.e("BXC", "No connection. Attempting to connect.");
setupConnection();
}
else
{
Log.i("BXC", "Xmpp Connection still valid");
}
Log.d("BXC", "isNull=" + (xConnection == null));
Log.d("BXC", "isConnected()=" + xConnection.isConnected());
Log.d("BXC", "isAuthenticated()=" + xConnection.isAuthenticated());
Log.d("BXC", "xmppConnectorRunning=" + Globals.backgroundXmppConnectorRunning);
Log.d("BXC", "socketIsClosed()=" + xConnection.isSocketClosed());
if(xConnection != null && xConnection.isConnected() == true)
{
Log.d("BXC", "Are we logged in?");
if(xConnection.isAuthenticated() == false)
{
Log.e("BXC", "Nope. Logging in...");
new LoginTask().execute();
}
else
{
Log.i("BXC", "Yes - Logged in.");
}
}
else if(xConnection == null || xConnection.isConnected() == false || xConnection.isAuthenticated() == false)
{
Log.e("BXC", "Disconnected. Attempting reconnect");
new LoginTask().execute();
}
else
{
Log.e("BXC", "Couldn't log in because connection failed.");
}
}
else
{
Log.e("BXC", "Already checking.");
}
// Schedule again for 5 minutes.
mHandler.postDelayed(checkConnection, mInterval);
}
// BINDER ////////////////////////////////////////////////////////////////////////////////
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
// INTERNAL CLASSES //////////////////////////////////////////////////////////////////////
public class XmppBinder extends Binder
{
public BackgroundXmppConnector getService(){
return BackgroundXmppConnector.this;
}
}
private class LoginTask extends AsyncTask<Void, Void, Void>
{
@Override
protected Void doInBackground(Void... params)
{
try
{
bConnecting = true;
synchronized(connectLock)
{
if(xConnection != null && (xConnection.isSocketClosed() || !xConnection.isConnected()))
{
xConnection.connect();
Log.i("BXC", "Login Credentials: " + Utility.getAndroidID(getApplicationContext()) + " / " + AppSettings.XMPP_KEYSTORE_PASSWORD);
xConnection.login(Utility.getAndroidID(getApplicationContext()), AppSettings.XMPP_KEYSTORE_PASSWORD);
xConnection.getChatManager().addChatListener(new ChatManagerListener(){
@Override
public void chatCreated(final Chat chat, boolean createdLocally)
{
if(!createdLocally)
{
// add chat listener //
chat.addMessageListener(new BackgroundMessageListener(getApplicationContext()));
}
}
});
Presence p = new Presence(Presence.Type.subscribe);
p.setStatus("Out and About");
xConnection.sendPacket(p);
Roster r = xConnection.getRoster();
r.setSubscriptionMode(SubscriptionMode.accept_all);
r.createEntry(AppSettings.BOT_NAME, "AbleBot", null);
r.addRosterListener(new RosterListener(){
@Override
public void entriesAdded(Collection<String> addresses)
{
for(String s : addresses)
{
Log.d("BXC", "Entries Added: " + s);
}
}
@Override
public void entriesDeleted(Collection<String> addresses)
{
for(String s : addresses)
{
Log.d("BXC", "Entries Deleted: " + s);
}
}
@Override
public void entriesUpdated(Collection<String> addresses)
{
for(String s : addresses)
{
Log.d("BXC", "Entries updated: " + s);
}
}
@Override
public void presenceChanged(Presence presence)
{
Log.d("BXC", "PresenceChanged: " + presence.getFrom());
}
});
}
}
}
catch(IllegalStateException ex)
{
Log.e("BXC", "IllegalStateException -->");
Globals.backgroundXmppConnectorRunning = false;
ex.printStackTrace();
}
catch(XMPPException ex)
{
Log.e("BXC", "XMPPException -->");
Globals.backgroundXmppConnectorRunning = false;
ex.printStackTrace();
}
catch(NullPointerException ex)
{
Log.e("BXC", "NullPointerException -->");
Globals.backgroundXmppConnectorRunning = false;
ex.printStackTrace();
}
catch(Exception ex)
{
Log.e("BXC", "Exception -->");
Globals.backgroundXmppConnectorRunning = false;
ex.printStackTrace();
}
return null;
//}
}
@Override
protected void onPostExecute(Void ignored)
{
if(xConnection != null)
{
if(xConnection.isConnected() && (!xConnection.isSocketClosed()))
{
Log.i("BXC", "Logged in to XMPP Server");
Globals.backgroundXmppConnectorRunning = true;
bConnecting = false;
}
else
{
Log.e("BXC", "Unable to log into XMPP Server.");
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}
}
else
{
Log.e("BXC", "Xmpp Connection object is null");
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}
}
}
}
答案 0 :(得分:1)
由于XMPPConnector
类中的内部变量/成员始终为true(初始启动除外),无论连接状态如何,都没有实际的方法。
我如何解决这个问题是创建一个全局静态变量,我设置为true / false,具体取决于连接状态,由回调方法定义,例如:
connectionClosed
,connectionClosedOnError
等。