Brandon Buck
Brandon Buck

Reputation: 7181

How can you programatically cancel reading from an InputStream?

I've looked around StackOverflow and with Google and was unable to find a solution to my problem, so here's what I'm doing.

I have a Server for a Console application, and users connect to it with any Telnet Client. I'm handling Clients with three separate threads, one thread (ClientThread) controls all Program access to a Client, the ClientThread maintains two threads, one for processing input and one for sending output. The ClienThread reads the client socket and sends the input (if any) to the ProcessingThread which processes the input and performs the actions the user dictated. The output Thread manages a queue of output that needs to be sent and sends it each time it wakes up. When a user disconnects I occasionally use Output that's left in the Output "queue" before the connection is terminated so I wanted to set it up so that the connection was kept alive until the Output Queue is empty - however the Thread that reads the socket (and ultimately closes it when there is no more output) is hanging on the read and I'm unable to close it. This wasn't a problem before when, upon the user disconnecting, I just closed the Socket. I'll give you the relevant code.

public class ClientThread extends Thread {
   // Initialization and other code not pertaining to the problem 

   public void run() {
      while (connected) {
         try {
            String input = in.readLine();

            if (input != null) {
               processor.queue(TextUtility.processBackspaceChars(input));
               timeoutTimer.interrupt();
            }
         } catch (Exception e) {
            if (e.getMessage() != null && !(e.getMessage().equals("socket closed")))
               server.appendError("Issue reading from client: "
                     + getClientDisplayInfo() + "\n"
                     + "&r-The issue is:&w- " + e.getMessage() + "&r-.");
         }
      }

      while (disconnecting) {
         try {
            if (outputThread.hasOutput()) {
               sleep(10);

            } else {
               disconnecting = false;
               outputThread.disconnect();
               client.close();
            }
         } catch (Exception exc) { 
            server.appendError("Failed to close the Thread for client: " + getClientDisplayInfo());
         }
      }  
   }   

   public void disconnect() {
      try {
         connected = false;
         disconnecting = true;
         processor.disconnect();
         timeoutTimer.disconnect();
         in.close(); // This is the BufferedReader that reads the Socket Input Stream
         this.interrupt(); // This was my attempt to break out of the read, but it failed

      } catch (Exception e) {
         server.appendError("Failed to close the Thread for client: " 
               + getClientDisplayInfo());
      }
   }
}

I'm just curious how I can cancel the read without closing the Socket since I need to continue sending output.

Upvotes: 3

Views: 763

Answers (2)

user207421
user207421

Reputation: 311050

Don't call available(): either you waste CPU calling it too frequently, or you waste time not calling it frequently enough, so your reponse times suffer. Set a read timeout on the Socket and have the reader thread check a 'cancel' flag every time it trips; set the flag from whereever you want to set it from.

Upvotes: 3

stacker
stacker

Reputation: 68992

I guess it is similar to the problems I faced yesterday You could invoke is.available() on your input stream and check whether data is available before doing a (blocking) read.

Upvotes: 4

Related Questions