2011-10-04 3 views
0

J'ai reçu une exception BindException lorsque j'ai redémarré mon application. Il agit comme un serveur en attente de messages de contrôle à distance. ServerSocket est en cours d'exécution dans un thread d'arrière-plan (AsyncTask). Après le redémarrage de mon application, je reçois toujours l'exception mentionnée ci-dessus. Je dois attendre comme 10 minutes jusqu'à ce qu'il puisse se lier à nouveau au port afin d'écouter."BindException: adresse déjà utilisée" après le redémarrage de l'application

J'ai essayé différents ports (tous> 50000) donc je suis sûr qu'il n'y a pas d'autre application bloquant mon port. J'ai essayé de faire attention à la fermeture du socket et j'ai essayé d'utiliser l'option SO_REUSEADDR. Aussi je suis sûr qu'il n'y a qu'une seule connexion ouverte au moment de l'exécution, depuis que je me suis connecté chaque socketbind.

Donc ce que je pense est que la connexion n'est pas fermée correctement. J'ai lu à propos de l'habitude des prises qui ne se ferment pas instantanément. Mais je ne peux pas attendre 10 minutes à chaque redémarrage de l'application et je n'ai pas trouvé un moyen de raccourcir ou de tuer cette fois.

Avez-vous des idées?

L'exception:

10-04 16:39:22.526: WARN/System.err(4974): java.net.BindException: Address already in use 
10-04 16:39:22.526: WARN/System.err(4974):  at org.apache.harmony.luni.platform.OSNetworkSystem.bind(Native Method) 
10-04 16:39:22.526: WARN/System.err(4974):  at dalvik.system.BlockGuard$WrappedNetworkSystem.bind(BlockGuard.java:275) 
10-04 16:39:22.526: WARN/System.err(4974):  at org.apache.harmony.luni.net.PlainSocketImpl.bind(PlainSocketImpl.java:165) 
10-04 16:39:22.526: WARN/System.err(4974):  at java.net.ServerSocket.<init>(ServerSocket.java:123) 
10-04 16:39:22.526: WARN/System.err(4974):  at java.net.ServerSocket.<init>(ServerSocket.java:74) 
10-04 16:39:22.526: WARN/System.err(4974):  at com.*******.remote.RemoteHandlerListener$1.doInBackground(RemoteHandlerListener.java:114) 

Le code:

ServerSocket server; 
try { 
    server = new ServerSocket(); 
    server.setReuseAddress(true); 
    server.bind(new InetSocketAddress(serverport)); 
} catch (IOException e) { 
    e.printStackTrace(); 
    return null; 
} 

while (true) { 
    BufferedReader inStream = null; 
    Socket client = null; 
    try { 
     client = server.accept(); 
     inStream = new BufferedReader(new InputStreamReader(client.getInputStream())); 
     // read from stream 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     if (inStream != null) { 
      try { 
       inStream.close(); 
      } catch (IOException e) { } 
     } 
     if (client != null) { 
      try { 
       client.close(); 
      } catch (IOException e) { } 
     } 
    } 
} 
try { 
    server.close(); 
} catch (IOException e) { } 

L'exception est levée sur la server.bind-déclaration.

EDIT: Cause du problème: Le thread ne se terminera pas automatiquement car l'appel accepté est bloqué. Le programme ne s'est pas terminé complètement et le socket n'était pas non lié.

Solution: Définissez SO_TIMEOUT sur le socket et recherchez isCancelled dans la boucle while(). De cette façon le thread finira si vous appelez cancel() dessus. Essayez d'imprimer la pile de toutes les exceptions interceptées.

+0

Pouvez-vous définir «redémarrage» et «thread de fond»? Êtes-vous en train de tuer l'application du gestionnaire de tâches et de la redémarrer, ou simplement en réinstallant le .apk? Lorsque vous indiquez un thread d'arrière-plan, utilisez-vous un AsyncTask ou un thread Java traditionnel et il est marqué en tant que démon? Tous ces éléments sont pertinents pour la manière dont le cycle de vie de l'application et la machine virtuelle fonctionnent avec les unités de concurrence. –

+0

En redémarrant je veux dire appuyer sur le bouton de retour dans l'activité de démarrage et ensuite le redémarrer en cliquant sur l'icône invoquant ainsi la méthode onDestroy où j'arrête le thread. Aucun gestionnaire de tâches ou réinstallation impliqué. Tuer l'application via taskmanager résout le problème mais n'est pas une vraie solution. –

+0

En tant que thread d'arrière-plan, j'utilise une asyncTask. –

Répondre

0

Cela aidera probablement beaucoup. Peut-être qu'il y a quelque chose qui ne va pas dans votre code que vous avez posté. Vous créez des blocs try-catch sans manipuler l'exception. Vous ne savez même pas s'il y en a.


Mise à jour: L'étape suivante consiste à s'assurer que votre application est réellement arrêtée. À la première vue de votre code vous jamais quitter votre boucle infinie de clients acceptants. Essayez de résoudre ce problème et ajoutez une instruction d'impression après la fermeture de la ServerSocket:

try { 
    server.close(); 
    System.out.println("Server successfully stopped."); 
} catch (IOException e) { } 

Assurez-vous que vous trouverez dans la sortie de votre application.

Et si vous voulez être bâclée, vous pouvez appliquer l'application (et ServerSocket) à l'arrêt à l'aide:

System.exit(0); 
+0

J'ai ajouté le printStackTrace() s manquant. Aucune autre exception n'est levée en dehors de BindException. –

+0

Ouais c'était le problème. Je n'ai pas interrompu le Thread mais j'ai vérifié si le thread devait s'arrêter (via isCancelled) et laisser le thread se tuer. Maintenant, que se passe-t-il s'il n'y a pas de connexion entrante? Oui, le thread ne se terminera pas puisque l'appel accept() bloque. De cette façon, le fil ne s'est pas arrêté. Erreur stupide;) –

0

I D'accord - Habituellement, cela indique que le redémarrage n'a pas réussi à mettre fin au processus de serveur correctement. D'une manière ou d'une autre, il fonctionne toujours et donc le port est toujours bloqué.

Attendre 10 minutes est un peu long. Vérifiez (si possible) si le processus java précédemment exécuté est terminé.

+0

C'était un indice utile. S'assurer que l'application est vraiment arrêtée en la tuant manuellement a aidé. Mais comment puis-je m'assurer que mon application est toujours terminée ou comment puis-je la terminer au redémarrage? –

+0

Identifiez le processus du système d'exploitation qui a été créé lorsque vous avez "démarré" l'application, puis vous savez lequel vous devez surveiller pour voir s'il existe toujours. Selon l'empaquetage du lanceur, ce sera le nom de l'exécutable lancé ou java. Tuer ce processus à partir du gestionnaire de tâches/liste de processus fermera le socket, mais il faut faire attention si le processus est susceptible de laisser un état incohérent sur le disque. Certaines applications moins robustes ne se relancent pas proprement lorsqu'elles ont été détruites dans des sections critiques. –

0

Si ce n'est pas déjà fait, vous devriez étudier le matériel de développement Android sur Activity Lifecycles.Le tl; dr de cet article est que le système d'exploitation Android ne garantit absolument pas le moment où une application sera tuée, sauf qu'elle peut arriver à tout moment, et c'est pourquoi ils fournissent l'onPause, onResume, onRestart, etc. Vous ne pouvez pas jamais garantir que votre application va toujours mourir complètement, mais vous pouvez effectuer votre propre nettoyage, et je vous recommande de tuer votre thread et de fermer votre socket (ou une autre gestion) à l'intérieur de onPause. En outre, lors de l'utilisation de sockets Java (que ce soit Android ou non), il n'est jamais recommandé de laisser la fin du programme être l'action qui ferme vos sockets. Vous devriez presque toujours les fermer vous-même dans une sorte de zone de nettoyage. Surtout quand il s'agit de threads.

Mise à jour: Vous avez dit que vous revenez et redémarrez. Cela n'appelle pas onDestroy. onDestroy n'est appelé que si le système d'exploitation a besoin de la mémoire et tue complètement votre application (l'équivalent de la supprimer dans le Gestionnaire des tâches)

+0

Vous avez raison. OnStop() aurait été le chemin à parcourir alors je pense. –

Questions connexes