简体   繁体   中英

java serial read() is waiting indefinitely - how to break it?

I have a serial device connected to my PI that I read data from it... everything is good , but sometime the cable move or the serial device is unplug.

then the

line = r.readLine();

get stuck

I have try to overcome this problem by:

BufferedReader r = new BufferedReader (newnputStreamReader(p.getInputStream()));     
         try 
            {
                line = r.readLine();
                if (line.length() == 0)
                {
                    logfile.append("problem");
                    logfile.close();
                    System.out.println("Problem");
                    TimeUnit.SECONDS.sleep(5);
                    break;
                }

            }
            catch (IOException e)
            {
                logfile.append(line);
                logfile.close();
            }

but it doens't do nothing (because I geuss he is still waiting for data) not even throw an exception how can I make him say I have a problem ? maybe to use a timer or something like this ? if no data for 5 seconds ?

Thanks ,

Your assumption in this case is right. The readLine() method of the BufferedReader has an internal while-loop which will retrieve all bytes from the underlying input stream and will only break if the arriving character is either \\n or \\r .

Think of it like:

while(lastChar != '\n' || lastChar != '\r')
{
     //read from stream
}

However once entered the method will not return. The only exceptions are the occurence of those two special characters or if the InputStream is closed (in which case null ist returned).

The trick is to no enter until there is something to read from the InputStream:

public static void main( String[] args ) throws IOException
{

  boolean awaitInput = true;

  while(awaitInput)
  {
    if(System.in.available() != 0)
    {
      awaitInput = false;
      // read logic
    }
  }
}

This is only one of many possible solutions and I used System.in as an example since it is a InputStream like any other as well. But there is also a method called BufferedReader#ready which returns true if there is something to read:

public static void main( String[] args ) throws IOException
{

  BufferedReader br = new BufferedReader( new InputStreamReader(System.in) );

  boolean awaitInput = true;

  while(awaitInput)
  {
    if(br.ready())
    {
      awaitInput = false;
      String line = br.readLine();
      // read logic
    }
  }
}

At last if you want a timeout you can easily do it yourself like this:

public static void main( String[] args ) throws IOException
{
  BufferedReader br = new BufferedReader( new InputStreamReader(System.in) );
  boolean awaitInput = true;
  long timeout = System.currentTimeMillis() + 5_000;
  //                                          ^^^^^ 5_000ms = 5 sec 

  while(awaitInput && System.currentTimeMillis() < timeout)
  {
    if(br.ready())
    {
      awaitInput = false;
      String line = br.readLine();
      // read logic
    }
  }
}

You can use CompletableFuture to read concurrently and be able to use a timeout.

// wrap the readLine into a concurrent call
CompletableFuture<String> lineFuture = CompletableFuture.supplyAsync(() -> r.readLine());
try {
    // do the call, but with a timeout
    String readLine = lineFuture.get(5, TimeUnit.SECONDS);
    // do stuff with the line you read
} catch (TimeoutException e) {
    // plug pulled?
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM