gpt4 book ai didi

Android XMPP 避免资源冲突

转载 作者:太空宇宙 更新时间:2023-11-03 12:54:16 42 4
gpt4 key购买 nike

我正在为我的 XMPP 连接/服务器使用 Smack 和 Openfire。但是我遇到了资源冲突这个非常(显然)常见的问题。谁能告诉我处理冲突的正确方法?

Openfire 设置为始终踢掉原始资源(这是一个定制平台,不向公众开放)。但是我仍然收到错误并且没有获得新的连接。我的 XMPP 类(class)如下。

package com.goosesys.gaggle.services;

import java.util.Collection;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.Connection;
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 org.jivesoftware.smack.packet.Presence.Type;

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;
import android.widget.Toast;

public class BackgroundXmppConnector extends Service
{
private ConnectionConfiguration acc;
private XMPPConnection xConnection;
private final IBinder mBinder = new XmppBinder();
private final Handler mHandler = new Handler();

private final int manualReconnectionTimer = (5 * 60 * 1000);

private static int mInterval1m = (2 * 60 * 1000);
private static int mInterval5m = (5 * 60 * 1000);
private static boolean bConnecting = false;
private static final Object connectLock = new Object();
private static final Object checkLock = new Object();

private final Runnable checkConnection = new Runnable()
{
@Override
public void run()
{
synchronized(checkLock)
{
Log.d("BXC", "Handler running - Checking connection");
checkConnectionStatus();
}
}
};

private final Runnable killConnection = new Runnable()
{
@Override
public void run()
{
synchronized(checkLock)
{
Log.d("BXC", "Killing connection and restarting");

// Manually disconnect and restart the connection every 5 minutes
if(xConnection != null)
xConnection.disconnect();

destroyConnectionAndRestart();
new LoginTask().execute();

mHandler.postDelayed(this, mInterval5m);
}
}
};

@Override
public void onCreate()
{
Log.i("BXC", "BackgroundXmppConnector Service has been created");

// Checks the connection state every 1 minute //
mHandler.postDelayed(checkConnection, mInterval1m);
mHandler.postDelayed(killConnection, mInterval5m);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("BXC", "Xmpp Connector Started");
new LoginTask().execute();

return Service.START_STICKY;
}

private void destroyConnectionAndRestart()
{
xConnection.disconnect();
xConnection = null;
Globals.backgroundXmppConnectorRunning = false;
bConnecting = false;
}

private void setupConnection()
{
Log.d("BXC", "Settting up XMPP connection");
try
{
if(!bConnecting && !Globals.backgroundXmppConnectorRunning)
{
acc = new ConnectionConfiguration(AppSettings.XMPP_SERVER_HOST,
AppSettings.XMPP_SERVER_PORT);
acc.setSecurityMode(SecurityMode.disabled);
acc.setSASLAuthenticationEnabled(false);
acc.setReconnectionAllowed(false);
acc.setSendPresence(true);

xConnection = new XMPPConnection(acc);
xConnection.addConnectionListener(new ConnectionListener()
{
@Override
public void connectionClosed()
{
Log.e("BXC", "Xmpp connection closed");
Globals.backgroundXmppConnectorRunning = false;
Globals.numberOfDisconnects += 1;
//destroyConnectionAndRestart();

Utility.writeToLog(getApplicationContext(), "Xmpp Connection closed - disconnected# (" + Globals.numberOfDisconnects + ")");
}

@Override
public void connectionClosedOnError(Exception e)
{
Log.e("BXC", "Xmpp connection closed with error: " + e);
Globals.backgroundXmppConnectorRunning = false;
Globals.numberOfDisconnectsOnError += 1;
// This is more than likely due to a conflict loop - it's best to disconnect and nullify
// our connection and let the software restart when it checks every 5 minutes
if(e.toString().toUpperCase().contains("CONFLICT"))
{
Log.e("BXC", "Conflict connection loop detected - Waiting");
}

Utility.writeToLog(getApplicationContext(), "Xmpp Connection closed with error [" + e + "] - disconnected# (" + Globals.numberOfDisconnectsOnError + ")");
}

@Override
public void reconnectingIn(int seconds)
{
Log.i("BXC", "Xmpp connection, reconnecting in " + seconds + " seconds");
Globals.backgroundXmppConnectorRunning = false;
bConnecting = true;
}

@Override
public void reconnectionFailed(Exception e)
{
Log.e("BXC", "Xmpp reconnection failed: " + e);
Globals.backgroundXmppConnectorRunning = false;
//destroyConnectionAndRestart();

Utility.writeToLog(getApplicationContext(), "Xmpp reConnection failed with error [" + e + "] - disconnected# (" + Globals.numberOfDisconnects + ")");
}

@Override
public void reconnectionSuccessful()
{
Log.i("BXC", "Xmpp reconnected successfully");
Globals.backgroundXmppConnectorRunning = true;
bConnecting = false;
}
});
}
else
{
Log.i("BXC", "Already in connecting state");
}

}
catch (Exception e)
{
Log.e("BXC", e.getMessage());
}
}

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);
//Toast.makeText(getApplicationContext(), "Packet sent to XMPP", Toast.LENGTH_LONG).show();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}


private void checkConnectionStatus()
{
Log.d("BXC", "Checking Xmpp connection status");

if(xConnection == null || xConnection.isAuthenticated() == false ||
xConnection.isConnected() == false || xConnection.isSocketClosed() ||
Globals.backgroundXmppConnectorRunning == false)
{
Log.e("BXC", "Connection to server is dead. Retrying");
Toast.makeText(getApplicationContext(), "Connection dead - retrying", Toast.LENGTH_SHORT).show();
destroyConnectionAndRestart();
new LoginTask().execute();
}
else
{
Log.i("BXC", "Connection appears to be valid");
Toast.makeText(getApplicationContext(), "Connection valid", Toast.LENGTH_SHORT).show();
}

}

// 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)
{
// First ensure we've got a connection to work with first
if(Utility.hasActiveInternetConnection(getApplicationContext()) &&
((!bConnecting) || (!Globals.backgroundXmppConnectorRunning)))
{
try
{
//bConnecting = true;
Log.d("BXC", "Beginning connection");
synchronized(connectLock)
{
setupConnection();
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 -->");
if(ex.getMessage().contains("Already logged in to server"))
{
Globals.backgroundXmppConnectorRunning = true;
}
else
{
Globals.backgroundXmppConnectorRunning = false;
Utility.writeExceptionToLog(getApplicationContext(), ex);

ex.printStackTrace();
}
}
catch(XMPPException ex)
{
Log.e("BXC", "XMPPException -->");
Globals.backgroundXmppConnectorRunning = false;
Utility.writeExceptionToLog(getApplicationContext(), ex);
ex.printStackTrace();
}
catch(NullPointerException ex)
{
Log.e("BXC", "NullPointerException -->");
Globals.backgroundXmppConnectorRunning = false;
Utility.writeExceptionToLog(getApplicationContext(), ex);
ex.printStackTrace();
}
catch(Exception ex)
{
Log.e("BXC", "Exception -->");
Globals.backgroundXmppConnectorRunning = false;
Utility.writeToLog(getApplicationContext(), ex.toString());
ex.printStackTrace();
}

return null;
}
else
{
Log.i("BXC", "No active internet data connection - will retry");
}

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;

mHandler.postDelayed(checkConnection, mInterval1m);
}
else
{
Log.e("BXC", "Unable to log into XMPP Server.");
Globals.backgroundXmppConnectorRunning = false;

destroyConnectionAndRestart();
}
}
else
{
Log.e("BXC", "Xmpp Connection object is null");
Globals.backgroundXmppConnectorRunning = false;
}
}
}

}

据我所知,openfire(当设置为始终启动时)将始终启动原始资源,然后允许新登录连接,但我根本看不到这一点。任何帮助是极大的赞赏。谢谢。

最佳答案

处理资源冲突的正确方法是除非万不得已,否则不要使用固定资源。如果您的客户端在登录时未指定任何资源,则服务器应为其分配一个随机生成的永远不会冲突的资源。

您需要指定固定资源的原因很少,因为大多数客户端无论如何都会隐藏您的联系人资源,还有其他原因可以说明为什么在每个连接上都有一个新资源是有利的(比如避免群聊不同步的常见错误,因为群聊的服务器没有意识到连接用户实际上是一个新 session )。

固定资源的一个大问题是重新连接循环,如果服务器配置为踢掉旧的冲突资源,两个客户端会反复踢对方。您应该确保在收到资源冲突错误时不会自动重新连接。

关于Android XMPP 避免资源冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23605562/

42 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com