2017-09-21 10 views
0

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 + "=&gt;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)에 연결하지 못했습니다. 시스템은 잠시 후에 서비스의 네트워크 활동을 차단하지만 결코 활동을하지 못하게한다고 생각합니다 (?).

+0

나는이 오류가 헤로인 에서뿐만 아니라 단순한 http 요청이 무거운 앱을 실행 한 후에도 같은 오류를 호출한다는 것을 알았다. java.net.ConnectException : 15000ms 이후에 /94.x.x.x (포트 80)에 연결하지 못했습니다. isConnected failed : ECONNREFUSED (Connection refused) – xdamir79

답변

0

Xiaomi 전화에서 백그라운드로 긴 네트워크 연결을 사용할 수 없습니다. MIUI는 잠시 후 모든 네트워크 연결을 차단합니다. 중요한 네트워크 연결의 경우 Android 시스템에서 우선 순위가 높은 Firebase Cloud Messaging을 사용할 수 있습니다. 필요한 배경 작업을 시작할 수 있습니다. 또한 수신 메시지를 사용자에게 알릴 수 있습니다. 이 메시지를받은 후, 사용자는 그것을 클릭하면 그의 활동으로 돌아가고 xmpp 연결이 복원됩니다.