smack/xmpp을 사용하여 채팅 응용 프로그램을 작성하려고합니다. ejabberd 서버를 설치했습니다. 내 프로그램이 잘 연결하여 메시지를 다른 클라이언트에게 보낼 수 있습니다. XMPP 서비스에는 STICKY 속성이 있습니다. 3D 게임과 같이 무거운 응용 프로그램을 실행 한 후에 문제가 나타납니다. 게임을하는 동안 는, 서버에 XMPP 연결이 서비스가 자동으로 다시 시작 게임을 종료하고 다시 연결을 시도 후, broked하지만 SMACKException가 나타납니다android smack java.net.ConnectException 연결이 거부되었습니다
이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 서비스에서 재 연결 관리자가 있습니다. 어떤 경우에는 정상적으로 작동하지만이 경우에는 아무런 문제가 없습니다.
이 예외를 잡으면 프로그래밍 방식으로 서비스를 다시 시작했지만이 방법이 도움이되지 않습니다. 응용 프로그램을 수동으로 언로드하고 다시 시작할 때만 도움이됩니다. 나는 30 초가 지난 후 서버가 xmpp 연결을 닫을 것이라고 생각하지만 왜 서비스를 다시로드하면 결과가 나오지 않습니까? 내 코드에 이상이 있는지 아는 사람 있습니까?
MyService 클래스 package 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 분 후에 작동하고 연결 거부 오류가 발생합니다. 활동으로 돌아 가면 오류가 사라집니다. 안드로이드 6.0.1 비슷한 상황에서 오류가 약간 다릅니다 java.net.SocketTimeoutException : 10000ms 후에 /94.130.25.242 (포트 80)에 연결하지 못했습니다. 시스템은 잠시 후에 서비스의 네트워크 활동을 차단하지만 결코 활동을하지 못하게한다고 생각합니다 (?).
나는이 오류가 헤로인 에서뿐만 아니라 단순한 http 요청이 무거운 앱을 실행 한 후에도 같은 오류를 호출한다는 것을 알았다. java.net.ConnectException : 15000ms 이후에 /94.x.x.x (포트 80)에 연결하지 못했습니다. isConnected failed : ECONNREFUSED (Connection refused) – xdamir79