2011-11-08 12 views
14

To jest prosty serwer TCP. Jak mogę zamknąć gniazdo po zakończeniu programu? Używam try/finally i spróbuj zamknąć gniazdo. Ale nie kończy bloku finally, kiedy wyjdę z programu.Jak mogę zamknąć gniazdo w prawidłowy sposób?

Ktoś może wiedzieć, jak zamknąć gniazdo w prawidłowy sposób?

try { 
     socket = new ServerSocket(port); 
     System.out.println("Server is starting on port " + port + " ..."); 
    }catch (IOException e){ 
     System.out.println("Error on socket creation!"); 
    } 

    Socket connectionSocket = null; 
    try{ 
     while(true){    
      try{ 
       connectionSocket = socket.accept(); 
       Thread t = new Thread(new ClientConnection(connectionSocket)); 
       t.start(); 
      }catch (IOException e) { 
       System.out.println("Error on accept socket!"); 
      } 
     } 
    }finally{ 
     this.socket.close(); 
     System.out.println("The server is shut down!"); 
    } 
+1

połączenia gniazda 'close()' w swój sposób ostatecznie zablokować lub obecnie z Java 7 można użyć try-with-blok zasobów i będzie zamknąć je dla Ciebie. http://www.javacodegeeks.com/2011/07/java-7-try-with-resources-explained.html –

+0

Musisz również sprawdzić wartość NULL przed wywołaniem 'close()' na wypadek, gdyby konstruktor 'ServerSocket' wyrzucił wyjątek. – unholysampler

+0

@Kit Ho, Jak kończy się aplikacja? – mre

Odpowiedz

0

Howcome the finally does not run? Prawdopodobnie while (true) powinny być zastąpione czymś takim

while (!shutdownRequested) 

alternatywnie można utworzyć hak zamykania, który obsługuje gniazdo bliską

+0

Nit-wybredna notatka, sprawdź Javadoc. Chcesz zamknąć, a nie niszczyć. http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html –

+0

nie dostał tego, czy możesz opracować więcej? –

+0

możesz spróbować, wiadomość "Serwer jest wyłączony, nie drukuje!" –

0

No, jak pan „exit” program? finally zostanie wykonany, jeśli zostanie zgłoszony wyjątek lub jeśli blok try zakończy jego wykonanie w "normalny" sposób, ale myślę, że może być "trudny" z powodu twojego while(true).

Aby zamknąć gniazdo, należy użyć opcji socket.close() i nie polecam funkcji niszczenia.

10

Po utworzeniu ServerSocket, można dodać zamknąć go na zakończenie JVM, coś takiego:

Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){ 
    try { 
     socket.close(); 
     System.out.println("The server is shut down!"); 
    } catch (IOException e) { /* failed */ } 
}}); 

Wywoływanie ServerSocket#close zakończy blokowania ServerSocket.accept połączenia, powodując jej rzucać SocketException. Należy jednak pamiętać, że bieżąca obsługa wyjątku IOException w pętli while oznacza, że ​​użytkownik ponownie wprowadzi pętlę while, aby spróbować zaakceptować na zamkniętym gnieździe. JVM nadal się zakończy, ale jest trochę zaniedbany.

Haki zamykające nie są uruchamiane po zamknięciu aplikacji konsoli w Eclipse (przynajmniej w systemie Windows). Ale działają, jeśli używasz CTRL-C Java w normalnej konsoli. Aby je uruchomić, należy normalnie zakończyć JVM, np. SIGINT lub SIGTERM zamiast SIGKILL (kill -9).

Prosty program, który można wykonać w Eclipse lub konsoli, pokaże to.

public class Test implements Runnable { 

    public static void main(String[] args) throws InterruptedException { 
    final Test test = new Test(); 
    Runtime.getRuntime().addShutdownHook(new Thread(){public void run(){ 
     test.shutdown(); 
    }}); 
    Thread t = new Thread(test); 
    t.start(); 
    } 

    public void run() { 
    synchronized(this) { 
     try { 
     System.err.println("running"); 
     wait(); 
     } catch (InterruptedException e) {} 
    } 
    } 

    public void shutdown() { 
    System.err.println("shutdown"); 
    } 
} 
+1

Czy są wykonywane ZAWSZE 'ShutDownHook' s? Czy jest to powszechna i bezpieczna praktyka polegania na nich? – Gevorg

+1

@Gevorg Jak mówi javadoc, ShutdownHooks są uruchamiane przez JVM przed wyjściem, gdy jest normalnie zakończone. Jeśli "zabijesz -9" proces Java, nie będą. Zauważyłem, że haki zamykające są używane niezawodnie do prawidłowego zamykania procesów serwera w komercyjnym oprogramowaniu dla przedsiębiorstw. – sudocode

+0

Jego problemem jest wyjście z pętli 'accept()' do bloku 'finally {}', a nie co zrobić, gdy już się tam dostanie. – EJP

7

Nie ma potrzeby w danym przypadku, system operacyjny będzie zamknąć wszystkie gniazda TCP dla Ciebie Po wyjściu z programu.

+4

Masz rację mówiąc, że system operacyjny zamknie wszystkie gniazda TCP po wyjściu z programu, ale nie chciałbym "nie mów" * Nie ma potrzeby "* we wszystkich przypadkach. Zależy to od tego, czy musisz zwolnić podsłuchany port przed wyjściem z tego programu (chociaż w tym przypadku powinno być OK, ponieważ OP chce go zamknąć po wyjściu programu) – xav

2

Od javadoc:

Środowisko wykonawcze Java automatycznie zamyka strumieni wejściowych i wyjściowych gniazdo klienta, a gniazdo serwera, ponieważ zostały one utworzony w try-with-zasobów oświadczeniu.

także

Sposób finalize() nazywany jest przez maszynę wirtualną Java (JVM) zanim program kończy działanie, aby nadać programowi szansę oczyścić i zasobów uwalnianiu. Programy wielowątkowe powinny zamykać wszystkie pliki i gniazda, których używają przed wyjściem, aby nie były narażone na głód.Wywołanie metody server.close() w metodzie finalize() kończy połączenie z gniazdem używane przez każdy wątek w tym programie.

protected void finalize(){ 
//Objects created in run method are finalized when 
//program terminates and thread exits 
    try{ 
     server.close(); 
    } catch (IOException e) { 
     System.out.println("Could not close socket"); 
     System.exit(-1); 
    } 
    } 
Powiązane problemy