IOException после тысяч вызовов создания сокетов

Почему IOException после тысяч вызовов создания сокетов?

Я сделал простой серверный код (Java), который принимает соединения, затем создает поток, считывает сокет и отправляет другой символ клиенту. Клиентский код начинает выполнять цикл (достаточно длинный, чтобы воспроизвести проблему) и в каждом цикле создает 50 потоков. в каждом потоке создается клиентский сокет на серверную машину и отправляет символ, а затем считывает из сокета символ, который сервер отправляет обратно. Затем и клиент, и сервер закрывают сокет.

Через некоторое время я замечаю, что на стороне клиента я получаю исключение при создании клиентского сокета. Есть ли какие-то ограничения, которые я должен учитывать, чтобы работать правильно, или это должно работать в бесконечном цикле?

Я имею в виду ситуации, когда, возможно, после достаточно длительного времени цикла клиентская сторона пытается связать новый сокет с портом на клиентской машине, который все еще привязан к сокету, который находится в состоянии ЗАКРЫТО, но этот период времени должен быть прошло, чтобы быть освобожденным еще не пройденным ядром. (извините, не знаю официального названия этого периода времени) Клиентская и серверная машины — это две системы Linux в VMware.


person wildfrontier    schedule 15.05.2013    source источник
comment
какое IOException...? и да, вы, скорее всего, используете все доступные порты, прежде чем их можно будет освободить. в чем именно ваш вопрос?   -  person jtahlborn    schedule 15.05.2013


Ответы (3)


Похоже, ваше соединение было разорвано.

Вы забыли правило №1 из Заблуждений распределенных вычислений: Сеть всегда надежна.

person duffymo    schedule 15.05.2013

Вы установили для параметра setReuseAddress значение true на вашем ServerSocket? Если нет, вам придется ждать довольно долго, прежде чем ядро ​​освободит сетевые ресурсы.

person gma    schedule 15.05.2013

Благодарю вас ! На самом деле это мой серверный код

public class TestServer {

  public void createThread() {
    System.out.println("createThread");
    ServerThread servThread = new ServerThread();
    servThread.start();   
  }

  public static final void main(String[] args) {

    ServerSocket server = null;

    try {
      System.out.println("Started");
      server = new ServerSocket(12345);
    }
    catch(IOException ex) {
      System.out.println("Server: Exception at socket creation: " + ex.getMessage());
    }

    try {
      while(true) {
        Socket clientSock = server.accept();
        System.out.println("Connection Accepted: server: "+clientSock.getLocalPort()+", Client: "+clientSock.getPort());
        ServerThread servThread = new ServerThread(clientSock);
        servThread.start();
      }
    }
    catch(IOException ex) {
      System.out.println("Server: Exception at socket accept: " + ex.getMessage());
    }

  }
}

class ServerThread extends Thread {

  private Socket sock;

  public ServerThread() {}

  public ServerThread(Socket sock) {
    this.sock = sock;
  }

  public void run() {
    InputStream is = null;
    OutputStream os = null;
    try {
      is = sock.getInputStream();
      os = sock.getOutputStream();
    }
    catch(IOException ex) {}  

    try {     
      int b = is.read();
      System.out.println("server: received = " + (char)b);
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at read = " + ex.getMessage());
    }

    try {
      os.write('R');
      os.flush();
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at write = " + ex.getMessage());
    }

    try {
      sock.close();
    }
    catch(IOException ex) {
      System.out.println("Server: IOException at close = " + ex.getMessage());
    }
  }
}

а это клиентская часть:

public class TestClient {

  public static void main(String[] args) {

    if (args.length != 4) {
      System.out.println("Usage: java TestClient <ServerIP> <nbThreads> <cycle> <delay>");
      System.exit(1);
    }

    String host   = args[0];
    int nbThreads = Integer.parseInt(args[1]);
    int cycle     = Integer.parseInt(args[2]);
    int delay     = Integer.parseInt(args[3]);

    for (int i = 0; i<cycle; i++) {
      for (int j = 0; j<nbThreads; j++) {
        ClientThread clThread = new ClientThread(host);
        clThread.start();
      }
/*      try {
        Thread.sleep(delay);
      }
      catch (Exception ex) {} */
    }
  }
}

class ClientThread extends Thread {

  private String host;

  public ClientThread(String host) {
    this.host = host;
  }

  public void run(){

    for (int i=0; i<3; i++) {
      Socket clientSock = null;
      try {
        clientSock = new Socket(host, 12345);
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at socket creation = " + ex.getMessage());
      }

      OutputStream os = null;
      InputStream  is = null;
      try {
        os = clientSock.getOutputStream();
        is = clientSock.getInputStream();
      }
      catch (IOException ex) { }

      try {
        os.write('B');
        os.flush();
      }
      catch (IOException ex) {
        System.out.println("Client: IOException at write = " + ex.getMessage());
      }

      try {
        int reply = is.read();
        System.out.println("Client: reply = " + (char)reply);
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at read = " + ex.getMessage());
      }

      try {
        clientSock.close();
      }
      catch(IOException ex) {
        System.out.println("Client: IOException at close = " + ex.getMessage());
      }
    }
  }
}

Я тестирую с 60 потоками и 1000 циклами и без задержки.

Я ошибся в своем первом вопросе, исключение возникает из-за вызова is.read() через некоторое время, и это исключение «Сброс соединения». Я сделал этот пример кода, чтобы имитировать проблему, с которой я сталкиваюсь в своем коде приложения, где я получаю исключение во время создания клиентского сокета... но, похоже, мне нужно найти дальше, в чем разница между этим и моим кодом приложения . Однако я думаю, что это поможет мне также понять, почему через некоторое время я получаю исключение «Сброс соединения» на стороне клиента через некоторое время. Возможно ли, что на стороне сервера, как только произошло os.write('R'), sock.close() происходит так быстро, что на стороне клиента вызов is.read() еще не достиг. Звучит странно :)

Также не уверен, в каком сокете я должен использовать функцию setReuseAddress. Не на стороне клиента, потому что там я снова и снова создаю сокеты... хотя теперь я не получаю исключение при создании клиентского сокета. Спасибо !

person wildfrontier    schedule 16.05.2013