InputStream没有检测到另一边何时关闭了OuputStrem和Socket

时间:2016-02-25 19:13:27

标签: java sockets exception inputstream outputstream

我举了一个我的情况的例子:

我有一个客户端产生双打数字(我真的需要发送字节)在另一边我有一个服务器参加客户端请求(这个例子只有一个),并创建一个工人......

问题是Worker(根据服务器接受的Socket创建的InputStream)没有检测到客户端(关闭OutputStream和Socket)何时终止。

这是我的代码:

客户端

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...时,必须至少完成ConsumerDouble,同时打印消息ConsumerDouble IOException: (the message Exception)

问题

  1. 什么原因导致异常没有被抛入while循环的Worker(ConsumerDouble)?
  2. 我该如何解决这个问题?
  3. PD: 我正在读...

    How to detect a remote side socket close?但是对我来说OutputStream正在检测InputStream什么时候关闭(问题是当InputStream关闭时,即使输出的Socket创建者(在另一方面)关闭,也没有检测到OutputStream!)< / p>

    Socket close vs Inputstream close与我的问题无关。

    谢谢!

2 个答案:

答案 0 :(得分:0)

  
      
  1. 什么原因导致异常没有被抛入while循环的Worker(ConsumerDouble)?
  2.   

为什么会这样?有什么例外?你有什么期待? available()信号流结束的方式是返回-1。但是,由于您从未测试或甚至不显示该值,因此您永远不会检测到流的结尾。您滥用read()时应该删除问题会使问题更严重。目前,只有在有数据需要立即读取时才会调用read(),这在流结束时永远不会成立。

  
      
  1. 我该如何解决这个问题?
  2.   

测试IOException返回-1。

您还有一条误导性消息,其中您声称缓冲区的长度是刚刚读取的字节数。事实并非如此。您也忽略了客户端中的{{1}}。不要那样做。

答案 1 :(得分:0)

您需要更改Worker中的某些内容,以检测另一方面是否已关闭OutputStream或Socket(要验证的InputStream对应项),抛出异常

第一个选项

利用您不使用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");
      }
    }