2014-11-24 3 views
1

Мой код выглядит следующим образом. Когда приходит запрос, сервер создает два потока (производитель-потребитель шаблон):многопоточный TCP-сервер: java.net.SocketException: Socket closed

... 
while(true) { 
    Socket clientSocket = server.accept(); 
    System.out.println("Got connection!"); 

    Thread consumerThread = new Thread(new ConsumerThread(sharedQueue, clientSocket)); 
    Thread producerThread = new Thread(new ProducerThread(sharedQueue, clientSocket)); 

    consumerThread.start(); 
    producerThread.start(); 
} 
... 

Потребитель нить читает то, что послал клиент и производитель нить отвечает обратно. Потребитель:

@Override 
    public void run() { 
     try { 
      while (true) { 
       in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 
       // read, do actions 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       in.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

Производитель:

@Override 
    public void run() { 
     try { 
      out = new PrintStream(clientSocket.getOutputStream(), true); 
      // some actions 
      out.println("something"); 

     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      try { 
       out.close(); 
       clientSocket.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

Но в сервере я получаю следующее сообщение об ошибке:

java.net.SocketException: Socket closed 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:150) 
    at java.net.SocketInputStream.read(SocketInputStream.java:121) 
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) 
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) 
    at java.io.InputStreamReader.read(InputStreamReader.java:184) 
    at java.io.BufferedReader.fill(BufferedReader.java:161) 
    at java.io.BufferedReader.readLine(BufferedReader.java:324) 
    at java.io.BufferedReader.readLine(BufferedReader.java:389) 
    at ee.ut.ds.server.ConsumerThread.run(ConsumerThread.java:30) 
    at java.lang.Thread.run(Thread.java:745) 

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

+0

Я думаю, что вы должны выполнить свою работу с потоком ввода и вывода в 1 потоке, чтобы правильно закрыть сокет. Если вы хотите обрабатывать входные и выходные данные параллельно: запустите новые потоки из потока, где вы обрабатываете ввод/вывод и используете правильную синхронизацию для закрытия сокета, когда вся работа выполняется. – pomkine

ответ

5

Вы закрыли сокет и продолжали использовать его.

Не закрывайте гнездо, или его выходной поток, пока вы не прочтете конец потока из BufferedReader.

Построить BufferedReader вне цикла.

Вам, вероятно, не нужно два потока на разъем.

+0

Построение 'BufferedReader' вне цикла не помогло. Я все еще получаю ту же ошибку. – Bob

+0

Вы закрыли сокет и продолжали его использовать. => где я использую его после того, как я его закрыл? – Bob

+0

Вам нужно сделать больше, чем просто одну из трех вещей, которые я рекомендовал здесь.Попробуйте прочитать весь ответ. Вы используете сокет после закрытия в том месте, где было исключено исключение. Вот почему он был брошен. Неужели это очевидно? – EJP

-1

Вы начинаете как параллельные потоки. Вы не можете предсказать поведение потоков. Вы используете тот же сокет для обоих потоков, и если поток производителей начинается, вы закрываете сокет в секции finally. вам не следует закрывать соединение и следить за состоянием гонки.

+1

Можете ли вы предложить, как мне изменить свой код? – Bob

+0

Точно. Довольно расплывчатый ответ. Все потоки выполняются параллельно. Вот почему они - потоки. – EJP

+0

вы закрываете сокет и все еще пытаетесь его использовать. – Shriram

-1

Проблема заключается в том, что вы закрываете сокет из своего продукта после того, как что-то ему написали. Если вы хотите, чтобы сокет был открыт, просто закройте выходной поток в блоке finally в Producer. Вы можете закрыть сокет от Server/Producer/Consumer, как только вы убедитесь, что сетевого сокета не происходит через сокет.

https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#close()

+0

Да, когда производитель отправляет сообщение клиенту, я не ожидаю никакой связи между этим клиентом и сервером. Поэтому я хочу закрыть этот сокет. И я делаю это в конце блока. Однако, если я удалю эту строку, которая закрывает сокет, я все равно получаю ту же ошибку. – Bob

+0

Закрытие выходного потока закроет сокет. И его входной поток. – EJP

+0

Это ожидается. Потому что, когда ваши потоки (Продюсер/Потребитель) заканчиваются, сокет закрывается. Попробуйте использовать свою логику prod/потребления внутри бесконечного цикла в вашем Продюсере и Потребителе. Что-то вроде, хотя (правда) {Продюсер/Потребительские операции}. И закрыть сокет с сервера –

Смежные вопросы