web-dev-qa-db-fra.com

Socket EADDRINUSE (adresse déjà utilisée)

Je fais de la programmation par socket. J'ai pris référence au lien ci-dessous:

http://examples.javacodegeeks.com/Android/core/socket-core/Android-socket-example/

Vous trouverez ci-dessous des détails sur mon problème. J'ai créé Android lib pour ce ServerThread (exigence de mon projet), et cela est utilisé dans l'application de test.

Maintenant, testez l'application pour vous connecter à cela via lib et faites le processus. La première fois, cela fonctionne parfaitement, mais si je ferme et rouvre, il se bloque exceptionnellement:

"EADDRINUSE (adresse déjà utilisée)"

Aussi essayé serverSocket.setReuseAddress(true) ceci mais pas de chance.

Mon code:

public void run() {
    Socket socket = null;
    try {
        serverSocket = new ServerSocket(SERVER_PORT);
        serverSocket.setReuseAddress(true);

    } catch (IOException e) {
        Log.e(TAG, "exception1= " + e.getMessage());
    }
    while (!Thread.currentThread().isInterrupted()) {
        try {

            socket = serverSocket.accept();
            Log.d(TAG, "server Connected.......!!!!");

            communicationThread = new CommunicationThread(
                    socket);
            commThread = new Thread(communicationThread);
            commThread.start();

        } catch (IOException e) {
            Log.e(TAG, "exception 2=" + e.getMessage());
        }
    }
}

Si j'appelle serverSocket.close(), l'exception 2 s'affiche lorsque le socket du serveur est fermé. Le fil de communication est identique à celui indiqué dans le lien précédent.

10
morya

Vous devez appeler setReuseAddress(true) avant que le socket ne soit lié au port. Vous l'appelez après, car vous transmettez le port au constructeur, qui liera immédiatement le socket.

Essayez ceci à la place:

serverSocket = new ServerSocket(); // <-- create an unbound socket first
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(SERVER_PORT)); // <-- now bind it
25
Remy Lebeau

Les sockets TCP (et probablement d'autres) ne peuvent pas réutiliser le même port pendant une période après la fermeture. Ceci afin d'éviter toute confusion s'il existe des données sur le réseau provenant d'une connexion existante. Vous pouvez remplacer ce comportement, mais la valeur par défaut consiste à attendre un certain temps avant de permettre la réutilisation du port. 

L'appel pour résoudre ce problème est setReuseAddress(true) sur le socket du serveur. Mais je ne suis pas sûr si elle doit être appelée sur la première prise ou sur la seconde, ou les deux.

Modifier:

Voici un article de blog décrivant l’état TCP de la socket TIME_WAIT et son existence: http://www.serverframework.com/asynchronousevents/2011/01/time-wait-and-its-design-implications -for-protocoles-and-scalable-servers.html

8
Gabe Sechan

Tandis que d’autres réponses soulignaient l’importance de setReuseAddress(true), un autre problème pouvant survenir est de construire deux fois le ServerSocket et d’appeler bind avec les mêmes paramètres. Par exemple, si vous appelez le code run() de la question par deux fois, serverSocket sera affecté à une nouvelle instance de la classe ServerSocket, mais l'ancienne sera toujours vivante jusqu'à ce que les ordures soient collectées. Construisez maintenant avec la valeur du port comme paramètre égal pour lier l'objet ServerSocket, et vous allez vous retrouver avec deux ServerSocket liés à la même adresse, ce qui est interdit, d'où l'exception. Alors construisez votre serverSocket avec le port choisi une seule fois!

2
AndrewBloom

Essayez de créer l'instance de SocketServer en dehors de la méthode run (). 

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)   
    try {
        // create a new instance of an unbound socket first
        serverSocket = new ServerSocket(); 
        } catch (IOException e) {
           e.printStackTrace();
        }
}
0
Marco Aurelio Silva