2016-02-25 8 views
1

Я сделал пример моей ситуации:InputStream не обнаруживает, когда в другой СТОРОНЕ OuputStrem и гнездо закрыты

У меня есть клиент продуцирующих Doubles номер (Really мне нужно отправить байты) на другой стороне у меня есть Сервер, присутствующий на запросе клиентов (для этого примера только один), и создает Работника ...

Проблема заключается в том, что рабочий (с InputStream, созданный в соответствии с Socket, принятый сервером) не обнаруживает, когда Клиент (закрывающий OutputStream и Socket) завершается.

Вот мой код:

Client

class ProducerDouble extends Thread { 
    private Socket consSocket = null; 
    private OutputStream output = null; 
    private byte[] innerBytes = null; 
    private boolean isRunning = false; 
    public ProducerDouble(String consHost , int consPort) { 
    try { 
     consSocket = new Socket(consHost, consPort); 
    } 
    catch (UnknownHostException e) { 
     System.out.println("Unknown host!"); 
    } 
    catch (IOException e) { 
     System.out.println("Consumer :"+e.getMessage()); 
    } 
    try { 
     if (!(consSocket == null)) { 
     output = consSocket.getOutputStream(); 
     } 
    } 
    catch (IOException e) { } 
    } 
    @Override 
    public void run() { 
    if (!(consSocket == null)) { 
     isRunning = true; 
     int read = 0; 
     while (isRunning) { 
     try { 
      if (!(innerBytes == null)) { 
      output.write(innerBytes, 0, innerBytes.length); 
      System.out.println("ProducerDouble "+innerBytes.length +" bytes written"); 
      innerBytes = null; 
      } else { 
      try { 
       Thread.sleep(2000); 
       String sSending = "The generated double is:"+Double.toString(Math.random()*100.0); 
       innerBytes = sSending.getBytes(); 
      } catch (InterruptedException ex) { } 
      } 
     } catch (IOException e) { } 
     } 
     try { 
     output.close(); 
     } catch (IOException e) { } 
     try { 
     consSocket.close(); 
     } catch (IOException e) { } 
     System.out.println("\n Exiting ProducerDouble...\n"); 
    } 
    } 

    public void stopExecute() { 
    isRunning = false; 
    } 
} 

работник

class ConsumerDouble extends Thread { 
    private Socket clientSocket = null; 
    private InputStream input = null; 
    private byte[] innerBytes = null; 
    private boolean isRunning = false; 

    public ConsumerDouble(Socket newClientSocket) { 
    clientSocket = newClientSocket; 
    try { 
     input = clientSocket.getInputStream(); 
    } catch (IOException e) { } 
    } 
    @Override 
    public void run() { 
    isRunning = true; 
    while (isRunning) { 
     System.out.println("ConsumerDouble running"); 
     try { 
     if (innerBytes == null) { 
      if (input.available() > 0) { 
      innerBytes = new byte[input.available()]; 
      int read = input.read(innerBytes, 0, innerBytes.length); 
      System.out.println("ConsumerDouble " + innerBytes.length 
       +" bytes read from Host "); 
      } else { 
      try { 
       Thread.sleep(1500); 
      } catch (InterruptedException ex) { } 
      } 
     } 
     } catch (IOException e) { 
     isRunning = false; 
     System.out.println("\nConsumerDouble IOException:"+e.getMessage()+"\n"); 
     } 
    } 
    System.out.println("\n ConsumerDouble Request Terminated...\n"); 
    try { if (input != null) input.close(); } catch (IOException e) { } 
    try { if (clientSocket != null) clientSocket.close(); } catch (IOException e) { } 
    } 

    public void stopExecute() { 
    isRunning = false; 
    } 
} 

Запуск и остановка сервера

if (jToggleButtonServer.isSelected()) { 
    thrdSrvrDouble = new Thread() { 
    @Override 
    public void run() { 
     try { 
     SrvrSocketDouble = new ServerSocket(1023); 
     System.out.println("ServerDouble Listening on port number: "+1023); 
     } catch (IOException e) { 
     System.out.println("Could not listen on port: "+1023); 
     } 
     bThrdServerDoubleRunning = true; 
     while (bThrdServerDoubleRunning) { 
     Socket clientSocket = null; 
     try { 
      clientSocket = SrvrSocketDouble.accept(); 
      System.out.println("New Client Address: " + clientSocket.getInetAddress() + " Port:" + clientSocket.getPort()); 
     } catch (IOException e) { 
      if(!bThrdServerDoubleRunning) { 
      System.out.println("ServerDouble Stopped.") ; 
      break; 
      } 
      throw new RuntimeException("Error: ServerDouble accepting client connections", e); 
     } 
     if (consumerDouble == null) { 
      consumerDouble = new ConsumerDouble(clientSocket); 
      consumerDouble.start(); 
     } 
     } 
     consumerDouble.stopExecute(); 
     System.out.println("\n Exiting ServerDouble!!!"); 
    } 
    }; 
    thrdSrvrDouble.start(); 
} else { 
    bThrdServerDoubleRunning = false; 
    try { 
    SrvrSocketDouble.close(); 
    } catch (IOException e) { } 
} 

Переменные

static ServerSocket SrvrSocketDouble; 
Thread thrdSrvrDouble = null; 
static boolean bThrdServerDoubleRunning = false; 
ProducerDouble producerDouble = null; 

Запуск и остановка клиента (ProducerDouble)

if (jToggleButtonProducer.isSelected()) { 
    String sConsHost = jtfSrClConsHost.getText(); 
    producerDouble = new ProducerDouble(sConsHost, 1023); 
    producerDouble.start(); 
} else { 
    producerDouble.stopExecute(); 
} 

В Ouput

run: 
ServerDouble Listening on port number: 1023 
New Client Address: /192.168.0.16 Port:51056 
ConsumerDouble running 
ConsumerDouble running 
ProducerDouble 41 bytes written 
ConsumerDouble running 
ConsumerDouble 41 bytes read from Host 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ProducerDouble 41 bytes written 

Exiting ProducerDouble... 

ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ConsumerDouble running 
ServerDouble Stopped. 

    Exiting ServerDouble!!! 

ConsumerDouble Request Terminated... 

BUILD SUCCESSFUL (total time: 2 minutes 0 seconds) 

Когда ProducerDouble заканчивает Exiting ProducerDouble..., по крайней мере, CustomerDouble должен быть завершен, также распечатывая сообщение ConsumerDouble IOException: (the message Exception)!

Вопрос

  1. Что является причиной для исключения не брошено в то время как петля Worker (ConsumerDouble)?
  2. Как я могу это решить?

PD: Я читал ...

How to detect a remote side socket close? но для меня OutputStream работает определить, когда InputStream закрывается (проблема с InputStream не обнаруживает, когда OutputStream закрыт, даже если сокет создатель выход (с другой стороны) закрыт)!

Socket close vs Inputstream close не имеет отношения к моему вопросу.

Спасибо!

ответ

0
  1. Что является причиной для исключения не брошено в то время как петля Worker (ConsumerDouble)?

Зачем это должно быть? Какое исключение? Что вы ожидаете? Способ, которым InputStream.read() сигнализирует конец потока, - это возврат -1. Однако, поскольку вы никогда не проверяете или даже не показываете это значение, вы никогда не обнаруживаете конец потока. Проблема усугубляется вашим неправильным использованием available(), которое вы должны просто удалить. В настоящее время вы вызываете только read(), когда есть данные, которые нужно прочитать немедленно, что никогда не будет истинным в конце потока.

  1. Как это решить?

Тест для read() возвращения -1.

У вас также есть вводящее в заблуждение сообщение, в котором вы утверждаете, что длина буфера - это количество только что прочитанных байтов. Это не так. Вы также игнорируете IOException в клиенте. Не делай этого.

+0

Reading: https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html#available-- Я ошибся с: Реализация этого метода в подклассе может вызывать исключение IOException, если этот входной поток был закрыт вызовом метода close(). –

+0

Вопрос: что происходит, когда на другой стороне (выходной поток не отправляется, но остается открытым)? Какое значение возвращается 'inputstream (read)' 0 или -1? –

+0

Размер массива байтов для приема байтов из 'inputstread.read (ArrayBytes)' вычисляется (I knpw, который не является точным) в соответствии с методом 'inputstread.available()'. –

0

Вам необходимо что-то изменить в своем Рабочем месте, чтобы обнаружить, когда на другой стороне он закрыл OutputStream или Socket (подтверждение для InputStream для проверки), throwing Исключения.

ПЕРВЫЙ ВАРИАНТ

Принимая преимущество, что вы не используете OutputStream (в ConsumerDouble) может заставить исключение отправки байт.

isRunning = true; 
while (isRunning) { 
    try { 
    clientSocket.getOutputStream().write(0); 
    } catch (IOException e) { 
    isRunning = false; 
    // Software caused connection abort: socket write error 
    } 
    System.out.println("ConsumerDouble running"); 
    // from here on the rest of the code will remain the same as it is in your. 

ВТОРОЙ ВАРИАНТ

Вы должны изменить логику приема используется

class ConsumerDouble extends Thread { 
    private Socket clientSocket = null; 
    private InputStream input = null; 
    private byte[] innerBytes = new byte [1024]; // Is not null! 
    private boolean isRunning = false; 
    private int read = 0; // moved from while loop! 

Полностью изменяя цикл While !!

while (isRunning) { 
     System.out.println("ConsumerDouble running"); 
     try { 
     read = input.read(innerBytes, 0, innerBytes.length); 
     System.out.println("ConsumerDouble " + read 
      +" bytes read from Host "); 
     byte[] nBytes = new byte[read]; 
     System.arraycopy(innerBytes, 0, nBytes, 0, read); 
     System.out.println("Received: " + new String(nBytes)); 
     } catch (IOException e) { 
     isRunning = false; 
     System.out.println("\nConsumerDouble IOException:"+e.getMessage()+"\n"); 
     } catch (NegativeArraySizeException e) { 
     isRunning = false; 
     System.out.println("\nConsumerDouble NegativeArraySizeException:"+e.getMessage()+"\n"); 
     } 
    } 

По рекомендации ...

while (isRunning) { 
     System.out.println("ConsumerDouble running"); 
     try { 
     read = input.read(innerBytes, 0, innerBytes.length); 
     if (read != -1) { 
      System.out.println("ConsumerDouble " + read 
       +" bytes read from Host "); 
      // this code is an example showing the message 
      byte[] nBytes = new byte[read]; 
      System.arraycopy(innerBytes, 0, nBytes, 0, read); 
      System.out.println("Received: " + new String(nBytes)); 
     } else { 
      isRunning = false; // the Stream was closed! 
     } 
     } catch (IOException e) { 
     isRunning = false; 
     System.out.println("\nConsumerDouble IOException:"+e.getMessage()+"\n"); 
     } 
    } 
+0

Это все еще не обнаруживает конец потока. Вы должны проверить для 'read == -1'. Предложение записи нулевого байта в конечном итоге остановится, если сверстник не читает. – EJP

+0

У вас есть причина, Извините, я пропустил часть кода. Soved! когда 'read = -1', исключение NegativeArraySizeException будет выбрано ... –

+2

Опираясь на побочный эффект ненужного фрагмента кода, не является приемлемым способом обнаружить что-либо, не говоря уже о конце потока. Выделение другого массива и копирование данных не требуется; поэтому может быть удалена во время проверки кода; и поэтому не является приемлемым способом обнаружения конца потока. Существует только один правильный путь, и я несколько раз приводил его здесь. – EJP