2010-06-12 21 views
5

Zasadniczo chcę stworzyć solidny serwer.Co zrobić, gdy ServerSocket zgłasza wyjątek IOException i utrzymuje serwer?

while (keepRunning.get()) { 
    try { 
     Socket clientSocket = serverSocket.accept(); 

     ... spawn a new thread to handle the client ... 
    } catch (IOException e) { 
     e.printStackTrace(); 
     // NOW WHAT? 
    } 
} 

W bloku IOException, co zrobić? Czy serwer jest uszkodzony i trzeba go odtworzyć? Na przykład poczekać kilka sekund, a następnie

serverSocket = ServerSocketFactory.getDefault().createServerSocket(MY_PORT); 

Jednak jeśli gniazdo serwera jest jeszcze OK, to szkoda, aby zamknąć go i zabić wszystkich uprzednio zaakceptowane połączenia, które są nadal komunikować.

EDYCJA: Po kilku odpowiedziach, oto moja próba radzenia sobie z wyjątkiem IOException. Czy wdrożenie gwarantowałoby utrzymanie serwera i ponowne utworzenie gniazda serwera tylko wtedy, gdy jest to konieczne?

while (keepRunning.get()) { 
    try { 
     Socket clientSocket = serverSocket.accept(); 

     ... spawn a new thread to handle the client ... 
     bindExceptionCounter = 0; 
    } catch (IOException e) { 
     e.printStackTrace(); 

     recreateServerSocket(); 
    } 
} 

private void recreateServerSocket() { 
    while (keepRunning) { 
     try { 
      logger.info("Try to re-create Server Socket"); 
      ServerSocket socket = ServerSocketFactory.getDefault().createServerSocket(RateTableServer.RATE_EVENT_SERVER_PORT); 

      // No exception thrown, then use the new socket. 
      serverSocket = socket; 
      break; 
     } catch (BindException e) { 
      logger.info("BindException indicates that the server socket is still good.", e); 
      bindExceptionCounter++; 

      if (bindExceptionCounter < 5) { 
       break; 
      } 
     } catch (IOException e) { 
      logger.warn("Problem to re-create Server Socket", e); 
      e.printStackTrace(); 

      try { 
       Thread.sleep(30000); 
      } catch (InterruptedException ie) { 
       logger.warn(ie); 
      } 
     } 
    } 
}  

Odpowiedz

4

W razie wątpliwości można spróbować ponownie utworzyć gniazdo serwera przy użyciu tego samego portu. Jeśli gniazdo zostało zamknięte, tworzenie się powiedzie i będzie można kontynuować przetwarzanie nowych połączeń. Stare połączenia zniknęły, ale to jest poza kontrolą, ponieważ gniazdo zostało zamknięte. Jeśli gniazdo nie zostało zamknięte, tworzenie nowej instancji zakończy się niepowodzeniem, ponieważ port jest nadal w użyciu, co można po prostu zignorować - tj. Nie zastępować bieżącego odniesienia do gniazda serwera.

Zasadniczo klienci powinni również założyć, że połączenia zostaną zerwane i konieczne będzie ponowne połączenie. Innymi słowy, nie tylko serwer musi być solidny - klienci powinni również przewidywać błędy połączenia i ponownie się z nim połączyć.

+0

Jeśli tworzenie nowego gniazda serwera, które kończy się niepowodzeniem z BindException - oznaczałoby to, że jest w 100% pewność, że stare gniazdo serwera jest w pełni poprawne? – s5804

+0

Nie mogę powiedzieć "tak" na pewno, ale ogólnie zakładam, że. Używałbym też strategii obronnej. Na przykład. jeśli otrzymasz X liczbę niepowodzeń wywoływania accept, możesz rozważyć uszkodzenie gniazda serwera i zamknąć gniazdo serwera. – mdma

1

Upewnij się rozróżniać różne IOException s można otrzymać. Czy jest to wyjątek podczas tworzenia połączenia? Czy jest to wyjątek po nawiązaniu połączenia?

Jedyny kod, który podałeś to accept() ing. Ogólnie rzecz biorąc, IOException zwykle oznacza błąd na dowolnej warstwie w sieci fizycznej.

Prawdopodobnie najlepszym zachowaniem awaryjnym, które można zastosować, jest oczekiwanie na kwant czasu, a następnie spróbuj ponownie nawiązać połączenie. Załóżmy, że najprawdopodobniej nie będzie możliwe ponowne połączenie, ponieważ utraciłeś połączenie sieciowe przez okres dłuższy niż tymczasowy. Upewnij się, że załatwisz to z wdziękiem. Jak wspomniała @mdma, musi to również być obsługiwane przez twoich klientów.

+0

reconnect - Masz na myśli ponowne utworzenie gniazda serwera? – s5804

+0

Jeśli zgubiłeś gniazdo, to tak ... –

1

Możesz uzyskać wyjątek IOException na accept(), jeśli gniazdo serwera jest zamknięte (przez ciebie) lub skończy Ci się zasób, np. uchwyty plików. Tak czy inaczej, niewiele można z tym zrobić. Jeśli serverSocket jest zamknięty (możesz to sprawdzić) prawdopodobnie miałeś dobry powód, aby to zrobić. W przypadku wyczerpania zasobów konieczne będzie zwiększenie limitu zasobów, co wymaga ponownego uruchomienia aplikacji lub wycieku zasobów.

+0

Jak sprawdzić, czy gniazdo jest zamknięte? Myślałem, że serverocket.isClosed() zawsze zwraca false, ponieważ wyższa warstwa nie otrzyma powiadomienia niższymi poziomami. Czy to jest poprawne? – s5804

1

Jednak jeśli gniazdo serwera jest nadal OK, to szkoda, aby je zamknąć i zabić wszystkich uprzednio zaakceptowane połączeń, które są nadal komunikować.

Należy pamiętać, że zamknięcie gniazda serwera NIE spowoduje zamknięcia wcześniej zaakceptowanych połączeń. Jak tylko połączenie zostanie zaakceptowane, żyje osobne, radosne życie w innym porcie.

Powiązane problemy