2016-11-14 5 views
1

Ich arbeite derzeit an einer Java-Netzwerk-Bibliothek und ich habe ein Problem mit DatagramSocket. Ich habe einen Thread, der auf UDP-Anfragen hört, und immer wenn ich es stoppe und den zugehörigen DatagramSocket schließe, wird es einen Thread geben, der sowieso nicht stoppt.Stoppen Sie einen DatagramSocket Thread

Hier ist ein Codebeispiel, das das Problem reproduziert:

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.SocketException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

class UDPListener implements Runnable { 

    private volatile boolean isRunning; 
    private volatile boolean clientClosed; 
    private int port; 
    private DatagramSocket client; 

    public UDPListener(int listeningPort) { 
     this.port = listeningPort; 
    } 

    public void open() throws SocketException { 
     this.clientClosed = false; 
     if (this.client != null) { 
      this.client.close(); 
     } 
     this.client = new DatagramSocket(this.port); 
    } 

    @Override 
    public void run() { 
     this.isRunning = true; 
     this.clientClosed = false; 
     DatagramPacket packet = new DatagramPacket(new byte[256], 256); 
     while (this.isRunning) { 

      try { 
       this.client.receive(packet); 
      } catch (SocketException e) { 
       if (!this.clientClosed) { 
        e.printStackTrace(); 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
     this.client.disconnect(); 
     System.out.println("stopped"); 
    } 

    public void stop() { 
     this.isRunning = false; 
     this.clientClosed = true; 
     this.client.close(); 
    } 


    public static void main(String[] args) throws InterruptedException, SocketException { 
     UDPListener t = new UDPListener(0); 
     ExecutorService e = Executors.newFixedThreadPool(1); 
     t.open(); 
     e.submit(t); 
     Thread.sleep(1000); 
     t.stop(); 
    } 
} 

ich das gleiche Problem mit dem Selector-Klasse haben.

Was mache ich falsch?

+0

Es scheint, dass ich nicht klar, in meiner Frage :(war der Thread gestartet mit dem Testamentsvollstrecker hält (“ stopped "wird angezeigt), aber es gibt einen Thread, den ich nicht explizit gestartet habe, der im Hintergrund läuft, wobei der Port verwendet wird und verhindert wird, dass die Anwendung beendet wird – Maliafo

Antwort

2

Sie haben vergessen, einen Anruf in die ExecutorService#shutdownNow() Methode aufzunehmen.

Ich habe mir die Freiheit genommen, den Code etwas zu überarbeiten und grundlegende Logging-Anweisungen hinzuzufügen, damit Sie sich vorstellen können, was der Code besser macht.

Hier ist ein Beispiel für die Ausgabe:

javac UDPListener.java && java UDPListener 
[main] Started main application. 
[main] Sleeping for 2000 
[pool-1-thread-1] Starting... 
[pool-1-thread-1] Opening datagram socket... 
[pool-1-thread-1] Opened datagram socket. 
[pool-1-thread-1] Waiting for datagrams... 
[main] Slept for 2000 
[main] Stopping all threads. 
[pool-1-thread-1] Interrupted while waiting for datagrams. 
[pool-1-thread-1] Stopped. 
[main] Stopped main application. 

Der feste Code ist unten:.

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.SocketException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

class UDPListener implements Runnable { 

    private volatile boolean isRunning; 
    private volatile boolean clientClosed; 
    private int port; 
    private DatagramSocket client; 

    public UDPListener(int listeningPort) { 
     this.port = listeningPort; 
    } 

    private void open() throws SocketException { 
     System.out.println(getName() + " Opening datagram socket..."); 
     this.clientClosed = false; 
     if (this.client != null) { 
      this.client.close(); 
     } 
     this.client = new DatagramSocket(this.port); 
     System.out.println(getName() + " Opened datagram socket."); 
    } 

    @Override 
    public void run() { 
     System.out.println(getName() + " Starting..."); 
     try { 
      this.open(); 

      this.isRunning = true; 
      this.clientClosed = false; 
      final DatagramPacket packet = new DatagramPacket(new byte[256], 256); 

      while (this.isRunning) { 
       System.out.println(getName() + " Waiting for datagrams..."); 
       try { 
        this.client.receive(packet); 
       } catch (SocketException e) { 
        if (!this.clientClosed) { 
         e.printStackTrace(); 
        } 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } finally { 
        System.out.println(getName() + " Interrupted while waiting for datagrams."); 
       } 
      } 
     } catch (SocketException se) { 
      se.printStackTrace(); 
     } finally { 
      this.client.disconnect(); 
      System.out.println(getName() + " Stopped."); 
     } 
    } 

    public void stop() { 
     this.isRunning = false; 
     this.clientClosed = true; 
     this.client.close(); 
    } 

    private static String getName() { 
     return "[" + Thread.currentThread().getName() + "]"; 
    } 


    public static void main(String[] args) throws InterruptedException, SocketException { 
     System.out.println(getName() + " Started main application."); 
     UDPListener t = new UDPListener(0); 
     ExecutorService e = Executors.newFixedThreadPool(1); 
     // t.open(); easier to debug if this call is exclusively done by UDPListener#run() 
     e.submit(t); 
     final int sleep = 2000; 
     System.out.printf(getName() + " Sleeping for %d\n", sleep); 
     Thread.sleep(sleep); 
     System.out.printf(getName() + " Slept for %d\n", sleep); 
     System.out.println(getName() + " Stopping all threads."); 
     t.stop(); 
     e.shutdownNow(); 
     System.out.println(getName() + " Stopped main application."); 
    } 
} 
Verwandte Themen