我正在尝试用smack / xmpp编写聊天应用程序。 我安装了ejabberd服务器。我的程序很好地连接到它可以发送 消息给其他客户。 XMPP服务有STICKY属性。 在运行像3D游戏这样繁重的应用程序后出现问 在玩游戏时,xmpp与服务器的连接断开,退出游戏后服务自动重启并尝试再次连接,但出现SMACKException:
09-20 15:46:06.540 31467-31533/home.chat E/(onCreate):SMACKException: The following addresses failed: '94.x.x.x:5222' failed because java.net.ConnectException: failed to connect to /94.x.x.x (port 5222) after 30000ms: isConnected failed: ECONNREFUSED (Connection refused)
我读到了这个错误的解释,这意味着: 表示尝试将套接字连接到远程地址和端口时发生错误。通常,远程拒绝连接(例如,没有进程正在侦听远程地址/端口)。
在我的xmpp服务中,我有Reconnection Manager。它在某些情况下工作正常,但在这种情况下没有任何作用。
在捕获此异常后,我尝试以编程方式重新启动服务,但这没有帮助。 只有手动卸载和重启应用程序才有帮助。 我认为服务器超时后30s关闭xmpp连接,但为什么重装服务没有给出结果? 有谁知道我的代码中有什么问题吗?
MyService类 包home.chat;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import java.io.File;
import java.util.Date;
public class MyService extends Service {
private static String DOMAIN = GlobalVariables.server;
private static String USERNAME = GlobalVariables.user_id;
private static String PASSWORD = GlobalVariables.user_password;
public static MyXMPP xmpp;
String text = "";
private LocalDb ldb;
private Boolean disconnectAppeared = false;
BroadcastReceiver br = null;
Date d1 = null;
Date d2 = null;
static MyService instance;
public static MyService getInstance(){
return instance;
}
@Override
public IBinder onBind(final Intent intent) {
return new LocalBinder<MyService>(this);
}
@Override
public void onCreate() {
super.onCreate();
instance = this;
checkInternetConnection();
xmpp = MyXMPP.getInstance(MyService.this, DOMAIN, USERNAME, PASSWORD);
connect();
Log.e("MyService"," created");
}
public static void connect(){
xmpp.connect("onCreate");
}
@Override
public int onStartCommand(final Intent intent, final int flags,
final int startId) {
return Service.START_STICKY;
}
@Override
public boolean onUnbind(final Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("MyService"," destroyed");
xmpp.disconnect();
unregisterReceiver(br);
Log.i("EXIT", "ondestroy!");
Intent broadcastIntent = new Intent("home.chat.ActivityRecognition.RestartService");
sendBroadcast(broadcastIntent);
}
private void checkInternetConnection() {
if (br == null) {
br = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
NetworkInfo info = (NetworkInfo) extras
.getParcelable("networkInfo");
NetworkInfo.State state = info.getState();
Log.d("TEST Internet", info.toString() + " "
+ state.toString());
if (state == NetworkInfo.State.CONNECTED & disconnectAppeared) { //on
xmpp.connect("After network changes");
disconnectAppeared = false;
}
if (state == NetworkInfo.State.DISCONNECTED) { //off
disconnectAppeared = true;
}
}
};
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(br, intentFilter);
}
}
public void destroyService(){
stopSelf();
}
}
MyXMPP课程
package home.chat;
import *;
public class MyXMPP {
public static boolean connected = false;
public static boolean loggedin = false;
public static boolean isconnecting = false;
public static boolean isToasted = false;
private boolean chat_created = false;
private String serverAddress;
public static XMPPTCPConnection connection;
public static String loginUser;
public static String passwordUser;
Gson gson;
static MyService context;
public static MyXMPP instance = null;
public static boolean instanceCreated = false;
private Handler mHandler = new Handler();
public static ReconnectionManager connMgr;
int[] rt_arr = {2,2,2,5,5,10,10};
int curr_delay = 0;
public static ConnectivityManager cm = null;
public NetworkInfo activeNetwork = null;
public static Roster myRoster;
static ArrayList<ChatMessage> msg_array = new ArrayList<ChatMessage>(); //буфер сообщений для отправки
public static ArrayList<HashMap<String,String>> msg_queue = new ArrayList<>();
public static ArrayList<HashMap<String,String>> stat_list = new ArrayList<>();
public String senderName = "";
public MyXMPP(MyService context, String serverAdress, String logiUser,
String passwordser) {
this.serverAddress = serverAdress;
this.loginUser = logiUser;
this.passwordUser = passwordser;
this.context = context;
init();
}
public static MyXMPP getInstance(MyService context, String server,
String user, String pass) {
if (instance == null) {
instance = new MyXMPP(context, server, user, pass);
instanceCreated = true;
Log.e("MyXMPP","create new instance");
}
return instance;
}
public org.jivesoftware.smack.chat.Chat Mychat;
ChatManagerListenerImpl mChatManagerListener;
MMessageListener mMessageListener;
String text = "";
String mMessage = "", mReceiver = "";
static {
try {
Class.forName("org.jivesoftware.smack.ReconnectionManager");
} catch (ClassNotFoundException ex) {
Log.e("E:","problem loading reconnection manager");
// problem loading reconnection manager
}
}
public void init() {
gson = new Gson();
mMessageListener = new MMessageListener();
mChatManagerListener = new ChatManagerListenerImpl();
initialiseConnection();
}
private void initialiseConnection() {
cm =
(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
activeNetwork = cm.getActiveNetworkInfo();
XMPPTCPConnectionConfiguration.Builder config = XMPPTCPConnectionConfiguration
.builder();
config.setSendPresence(true);
config.setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.required);
config.setCompressionEnabled(true);
config.setServiceName(GlobalVariables.service);
config.setHost(serverAddress);
config.setPort(5222);
config.setDebuggerEnabled(true);
try {
SSLContext sc = SSLContext.getInstance("TLS");
MemorizingTrustManager mtm = new MemorizingTrustManager(context);
sc.init(null, new X509TrustManager[] { mtm }, new java.security.SecureRandom());
config.setCustomSSLContext(sc);
config.setHostnameVerifier(mtm.wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier()));
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
} catch (KeyManagementException e) {
throw new IllegalStateException(e);
}
connection = new XMPPTCPConnection(config.build());
XMPPConnectionListener connectionListener = new XMPPConnectionListener();
connection.addConnectionListener(connectionListener);
PingManager pingManager = PingManager.getInstanceFor(connection);
pingManager.setPingInterval(900); // 15 min
pingManager.registerPingFailedListener(new PingFailedListener(){
@Override
public void pingFailed() {
// Do operation to handle if ping fail like force reconnect etc
Log.e("PingManager","Ping Failed, reconnection");
connected = false;
chat_created = false;
loggedin = false;
//disconnect();
connect("ping_manager");
}
});
ServerPingWithAlarmManager.getInstanceFor(connection).isEnabled(); //для пинга во время глубокого сна
}
public void disconnect() {
new Thread(new Runnable() {
@Override
public void run() {
connection.disconnect();
}
}).start();
}
public void connect(final String caller) {
AsyncTask<Void, Void, Boolean> connectionThread = new AsyncTask<Void, Void, Boolean>() {
@Override
protected synchronized Boolean doInBackground (Void...arg0){
if (connection.isConnected())
return false;
isconnecting = true;
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, caller + "=>connecting....", Toast.LENGTH_LONG).show();
}
});
Log.e("Connect() Function", caller + "=>connecting....");
try {
connection.setPacketReplyTimeout(20000);
// Enable automatic reconnection
connMgr = ReconnectionManager.getInstanceFor(connection);
connMgr.enableAutomaticReconnection();
connMgr.setFixedDelay(2);
//connMgr.setDefaultFixedDelay(1);
//connMgr.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.FIXED_DELAY);
connection.connect();
DeliveryReceiptManager dm = DeliveryReceiptManager
.getInstanceFor(connection);
dm.setAutoReceiptMode(AutoReceiptMode.always);
dm.addReceiptReceivedListener(new ReceiptReceivedListener() {
@Override
public void onReceiptReceived(final String fromid,
final String toid, final String msgid,
final Stanza packet) {
}
});
connected = true;
MainActivity.fConn = true;
} catch (IOException e) {
if (isToasted)
new Handler(Looper.getMainLooper())
.post(new Runnable() {
@Override
public void run() {
Toast.makeText(
context,
"(" + caller + ")"
+ "IOException: ",
Toast.LENGTH_SHORT).show();
}
});
Log.e("(" + caller + ")", "IOException: " + e.getMessage());
} catch (SmackException e) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Toast.makeText(context, "(" + caller + ")" + "SMACKException: ", Toast.LENGTH_SHORT).show();
}
});
Log.e("(" + caller + ")",
"SMACKException: " + e.getMessage());
//mHandler.post(checkConn); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<-- Problem place
//instance = null;
//MyService.getInstance().destroyService();
} catch (XMPPException e) {
if (isToasted)
new Handler(Looper.getMainLooper())
.post(new Runnable() {
@Override
public void run() {
Toast.makeText(
context,
"(" + caller + ")"
+ "XMPPException: ",
Toast.LENGTH_SHORT).show();
}
});
Log.e("connect(" + caller + ")",
"XMPPException: " + e.getMessage());
}
return isconnecting = false;
}
} ;
connectionThread.execute();
}
public static void login() {
try {
Log.e(loginUser,passwordUser);
loginUser = GlobalVariables.user_id;
passwordUser = GlobalVariables.user_password;
connection.login(loginUser, passwordUser);
Log.e("LOGIN", "Yey! We're connected to the Xmpp server!");
sendBufMessages();
myRoster = Roster.getInstanceFor(connection);
if (!myRoster.isLoaded()) {
try{ myRoster.reloadAndWait(); }
catch (Exception e) {System.out.println(e);}
}
myRoster.setDefaultSubscriptionMode(Roster.SubscriptionMode.accept_all);
myRoster.addRosterListener(new RosterListener() {
public void entriesAdded(Collection<String> addresses) {}
public void entriesDeleted(Collection<String> addresses) {}
public void entriesUpdated(Collection<String> addresses) {}
public void presenceChanged(Presence presence) {
Log.e("Roster","Presence changed: " + presence.getFrom() + " " + presence);
String uname = presence.getFrom();
int pos = uname.indexOf('@',0);
uname = uname.substring(0,pos);
Presence.Type ptype = presence.getType(); //Presence.type.available
for(int i=0;i<stat_list.size();i++){
HashMap<String,String> item = new HashMap<String, String>();
item = stat_list.get(i);
if (uname.equals(item.get("user_id").toString())) { stat_list.remove(i); break;}
}
HashMap<String,String> item = new HashMap<>();
item.put("user_id",uname);
if (ptype == Presence.Type.available){ item.put("onl","true"); }
if (ptype == Presence.Type.unavailable){ item.put("onl","false"); }
stat_list.add(0,item);
if (MainActivity.chatlist_selected) { ChatList.getInstance().startStatProc(); }
if (GlobalVariables.onchat == true & GlobalVariables.vuser_id.equals(uname)){
if (ptype == Presence.Type.available) { Chat.setUserStatus("onl"); }
if (ptype == Presence.Type.unavailable) {Chat.setUserStatus("offl");}
}
}
});
} catch (XMPPException | SmackException | IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private class ChatManagerListenerImpl implements ChatManagerListener {
@Override
public void chatCreated(final org.jivesoftware.smack.chat.Chat chat,
final boolean createdLocally) {
if (!createdLocally)
chat.addMessageListener(mMessageListener);
}
}
public void sendMessage(ChatMessage chatMessage) {
.....
}
public class XMPPConnectionListener implements ConnectionListener {
@Override
public void connected(final XMPPConnection connection) {
Log.e("xmpp", "Connected!");
connected = true;
curr_delay = 0; connMgr.setFixedDelay(2);
login();
}
@Override
public void connectionClosed() {
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(context, "ConnectionCLosed!",
Toast.LENGTH_SHORT).show();
}
});
Log.d("xmpp", "ConnectionCLosed!");
connected = false;
chat_created = false;
loggedin = false;
}
@Override
public void connectionClosedOnError(Exception arg0) {
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "ConnectionClosedOn Error!!",
Toast.LENGTH_SHORT).show();
}
});
Log.e("xmpp", "ConnectionClosedOn Error!");
connected = false;
chat_created = false;
loggedin = false;
}
@Override
public void reconnectingIn(int arg0) {
Log.e("xmpp", "Reconnectingin " + arg0);
if (arg0==0 & curr_delay<5){
curr_delay++;
connMgr.setFixedDelay(rt_arr[curr_delay]);
}
loggedin = false;
}
@Override
public void reconnectionFailed(Exception arg0) {
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "ReconnectionFailed!",
Toast.LENGTH_SHORT).show();
}
});
Log.d("xmpp", "ReconnectionFailed!");
connected = false;
chat_created = false;
loggedin = false;
}
@Override
public void reconnectionSuccessful() {
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(context, "REConnected!",
Toast.LENGTH_SHORT).show();
}
});
Log.d("xmpp", "ReconnectionSuccessful");
curr_delay = 0; connMgr.setFixedDelay(2);
connected = true;
//MainActivity.fConn = true;
chat_created = false;
loggedin = false;
}
@Override
public void authenticated(XMPPConnection arg0, boolean arg1) {
Log.d("xmpp", "Authenticated!");
loggedin = true;
ChatManager.getInstanceFor(connection).addChatListener(
mChatManagerListener);
chat_created = false;
new Thread(new Runnable() {
@Override
public void run() {
try {
sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
if (isToasted)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(context, "Connected!",Toast.LENGTH_SHORT).show();
}
});
}
}
private class MMessageListener implements ChatMessageListener {
@Override
public void processMessage(final org.jivesoftware.smack.chat.Chat chat,
final Message message) {
Log.i("MyXMPP_MESSAGE_LISTENER", "Xmpp message received: '"
+ message);
...
}
}
private Runnable checkConn = new Runnable() {
public void run() {
try {
Socket socket = new Socket(host, 5222);
socket.shutdownInput();
socket.shutdownOutput();
socket.close();
} catch(Exception e){Log.e("Socket",e.toString());}
disconnect();
Log.e("MyXMPP","disconnect");
mHandler.postDelayed(checkConn2,3000);
}
};
private Runnable checkConn2 = new Runnable() {
public void run() {
connect("After SmackException");
}
};
}
更新26.09.17。经过几天的实验,我仍然没有找到解决方案。 我尝试使用前台服务,PingManager,broadcastreceiver来重新创建服务,但没有结果。现在我尝试在系统内存不足时向应用程序使用压力信号。 更新05.10.17我仍然没有找到解决方案。我在Android 4.1.2上测试了这个程序。它工作正常。在Android 5.1.1上,它在退出活动后大约3分钟工作,然后我收到连接拒绝错误。当我返回活动时,错误消失。在Android 6.0.1上类似的情况,但是java.net.SocketTimeoutException的错误略有不同:10000ms后无法连接到/94.130.25.242(端口80)。我认为系统会在一段时间后阻止服务中的网络活动,但从不在活动中阻止(?)。
答案 0 :(得分:0)
在小米手机上无法在后台使用长网络连接。它会在一段时间后阻止任何网络连接。对于关键网络连接,您可以使用Firebase Cloud Messaging,它在Android系统中具有高优先级。它可以启动必要的后台工作。 它还可以通知用户有关传入的消息。接收此消息后,用户将单击该消息并返回其活动,并将恢复xmpp连接。
答案 1 :(得分:0)
尝试在您的AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND"/>
然后在您的服务中将以下代码编码到onCreate()
。我希望它能帮助某人。
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
Log.d(TAG, "PowerManager.SCREEN_DIM_WAKE_LOCK+PowerManager.ON_AFTER_RELEASE");
pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK + PowerManager.ON_AFTER_RELEASE, "wetwars:activityrecognition").acquire();
pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "WetWars:WakeLockActivity").acquire();
}