2012-10-19 20 views
10

Przeprowadziłem kilka testów z gniazdami i spotkałem się z dziwnym zachowaniem: ServerSocket odmówi połączenia po podłączeniu 50. gniazda klienta, nawet jeśli to gniazdo klienta zostanie zamknięte przed następnym otwarciem, a nawet jeśli opóźnienie jest dodawane między połączeniami.Limit połączeń Java ServerSocket?

Poniższy program jest moim eksperymentalnym kodem, który w swoim obecnym stanie nie zgłasza żadnych wyjątków i kończy normalnie. Jeśli jednak rozmiar tablicy Socket[] clients wzrośnie powyżej 50, gniazda klienta próbujące połączyć się po 50. połączeniu zostaną odrzucone przez gniazdo serwera.

Pytanie: Dlaczego liczba 50 jest liczbą, na którą połączenia gniazda są odrzucane przez gniazdo serwera?

public static void main(String[] args) { 
    try (ServerSocket server = new ServerSocket(2123)) { 
     Socket[] clients = new Socket[50]; 
     for (int i = 0; i < clients.length; i++) { 
      clients[i] = new Socket("localhost", 2123); 
      System.out.printf("Client %2d: " + clients[i] + "%n", i); 
      clients[i].close(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

mam uruchomić testy, gdzie kolejne 50 gniazd połączyć się z innym lokalnym serwerze, a nie problem wystąpił z 100 gniazda są otwierane i zamykane, więc już wywnioskować, że jego gniazdo serwer odmawia połączenia, a nie niektóre ograniczenia otwierania gniazd klientów, ale nie mogłem odkryć, dlaczego gniazdo serwera jest ograniczone do 50 połączeń, nawet jeśli nie są one jednocześnie połączone.

Odpowiedz

12

To wszystko w JavaDoc:

Maksymalna długość kolejki dla przychodzących wskazań połączeniowych (a żądanie połączenia) jest ustawiony na 50. Jeżeli oznaczenie połączenie nadejdzie, gdy kolejka jest pełna, w związku odmawia się.

Najwyraźniej Twój ServerSocket nigdy nie akceptuje żadnych połączeń, tylko nasłuchuje. Musisz albo zadzwonić accept() i rozpoczęcie obsługi połączenia lub zwiększyć przetwarza kolejkę zaległości rozmiar:

new ServerSocket(port, 100) 
+2

Czy połączenia w kolejce nie zostałyby usunięte, gdy gniazda klienta są zamknięte? – Vulcan

+1

@Vulcan Oczywiście nie. – EJP

+1

@EJP Tak, ale dlaczego by nie?Dla mnie wydaje się dziwne, że zamknięte gniazda pozostają w kolejce do połączenia. Domyślam się, że nie ma sposobu, aby gniazdo serwera mogło wiedzieć, że gniazdo klienta zostało zamknięte. – Vulcan

2

Oto przykład, który działa zgodnie z użytkownika @ TomaszNurkiewicz odpowiedź:

import java.net.*; 
import java.util.concurrent.atomic.AtomicBoolean; 

public class SockTest{ 
public static void main(String[] args) { 
    final AtomicBoolean shouldRun = new AtomicBoolean(true); 
    try { 
     final ServerSocket server = new ServerSocket(2123); 
     Thread serverThread = new Thread(){ 
      public void run() { 
       try { 
       while(shouldRun.get()) { 
       Socket s = server.accept(); 
       s.close(); 
      Thread.sleep(1); 
       } 
       } catch(Exception ex) { 
       ex.printStackTrace(); 
       } 
      } 
     }; 
     serverThread.start(); 
     Socket[] clients = new Socket[150]; 
     for (int i = 0; i < clients.length; i++) { 
      clients[i] = new Socket("localhost", 2123); 
      System.out.printf("Client %2d: " + clients[i] + "%n", i); 
      clients[i].close(); 
     } 
     shouldRun.set(false); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } finally { 
     shouldRun.set(false); 
    } 

    } 
} 
+0

Dzięki; Tak naprawdę stworzyłem podobny przykład po tym, jak widziałem odpowiedź @ TomaszNurkiewicza wcześniej, ale nie tak czysto jak twoja (zapomniałem o AtomicBoolean i stworzyłem własną prowizoryczną klasę z tą samą funkcjonalnością haha). +1 – Vulcan

0

Dwie rzeczy, które maja spójrz na:

  1. Serwer nie przyjmuje połączenia.
  2. Serwer nie może obsłużyć zbyt wielu połączeń w tym samym czasie. Może to być spowodowane zwiększeniem zaległości (powyżej 50). Spróbuj podać pewną przerwę czasową w milli sekundach, zanim ponownie nawiążesz połączenie z serwerem. Podobnie jak połączenia rampowe. Rozwiązałem go, dając trochę luki czasowej, gdy uruchomiłem obciążenie testowe.
Powiązane problemy