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

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?
}

Related

How to make fast data reading using socket in Java?

I'm using SocketChannel for single connection like this:
int sampleBufferSize = 50;
StringBuilder data = new StringBuilder();
ByteBuffer bf = ByteBuffer.allocate(sampleBufferSize);
SocketChannel sc = new SocketChannel();
while(true)
if(sc.read(bf) > 0){
bf.flip();
while(bf.hasRemaining())
data.append((char) bf.get());
bf.clear();
}else{
fireDataReceived(data.toString());
data.delete(0, data.length());
}
This code is not very efficient, but it reads HTTP POST request 130 KB from the same PC in 0.05 seconds. Now I'm trying to write a class with similar functionality but using Socket. Here is the code:
private static final int TIMEOUT_MILLIS = 50;
private boolean reading = false;
private long readBeginTime = 0;
private StringBuilder buffer = new StringBuilder();
private Thread thread = new Thread(){
public void run(){
while(!isInterrupted()){
try {
int b = getInputStream().read();
if(b == -1){
if(reading)
fireDataReceived();
close();
}else{
if(!reading){
reading = true;
readBeginTime = System.currentTimeMillis();
setSoTimeout(TIMEOUT_MILLIS);
}
buffer.append((char) b);
}
} catch (SocketTimeoutException e){
fireDataReceived();
} catch (IOException e) {
e.printStackTrace();
if(reading)
fireDataReceived();
close();
}
}
}
};
private void fireDataReceived(){
BufferedSocketEvent e = new BufferedSocketEvent(this, System.currentTimeMillis() - readBeginTime, buffer.toString());
buffer.setLength(0);
reading = false;
try {
setSoTimeout(0);
} catch (SocketException e1) {
e1.printStackTrace();
}
for(BufferedSocketListener listener: listeners)
listener.dataReceived(e);
}
And the problem is that it takes 0.4 seconds for the same request and I have no idea why does it take so long. Please, explain what is wrong with my code.
The problem with your streams code is that you're reading a byte at a time, which is slow, and also appending to the StringBuilder one at a time, ditto. Try this:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());
char[] chars = new char[8192];
int count;
while ((count = in.read(chars)) > 0)
{
buffer.append(chars, 0, count);
fireDataReceived();
}
Note that it isn't correct to use read timeouts as a means to separate requests. You need to parse the data to do that. TCP is a streaming protocol without message boundaries, and there are no guarantees about separate sends being received separately.
You have to use readLine() or similar method. End of HTTP header is marked by empty line. If you don't detect lines you cannot know when to stop reading data. Relying on timeouts or TCP fragments is not a correct solution. If request doesn't contain new line, you need to wait until one appears or the connection is terminated/timed out. You should wait at least a couple of seconds.
I would also get rid of those listeners. Being able to add multiple listeners for single socket might seem like a good idea but the only sensible thing to do with HTTP header is to parse it. The parser also needs to inform the reader when to stop reading.
I would start with something like this:
ServerSocket serverSocket = new ServerSocket(8888);
Socket clientSocket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "ASCII"));
String[] r = reader.readLine().split(" ");
String type = r[0];
String resource = r[1];
String version = r[2];
Map<String, String> headers = new HashMap<String,String>();
while(true) {
String line = reader.readLine();
if(line.isEmpty()) {
break;
}
String headerLine[] = line.split(":",2);
headers.put(headerLine[0],headerLine[1].trim());
}
processHeader(type, resource, version, headers);

PipedReader never ready() at end of stream

I'm trying to write code that reads from a Reader in a non-blocking way, i.e. only calling read() after ensuring ready() returns true.
To test the code, I use the PipedReader/PipedWriter combo, and ready() works great, until I close the PipedWriter, which also marks the end of the stream on the side of PipedReader. However, although its ready() method will never again return true, read() instantly returns -1 when called.
In this case, is there a non-blocking way to figure out that a call to read() would not block?
Here's an example that reproduces the issue.
package test;
import java.io.*;
public class Piper
{
public static void main(String[] args) throws Exception
{
int sleepBetweenChars = 100;
boolean throttle = true;
Reader reader = new StringReader("abc");
if (throttle)
reader = throttle(sleepBetweenChars, reader);
while (true)
{
if (reader.ready())
{
int c = reader.read();
System.out.println("Read " + c);
if (c == -1)
break;
}
else
{
System.out.println("Not ready");
Thread.sleep(sleepBetweenChars);
if (!reader.ready())
{
System.out.println("Still not ready, sleep some more");
Thread.sleep(20 * sleepBetweenChars);
if (!reader.ready())
{
int c = reader.read();
System.out.println("Still not ready, we read nonetheless: " + c);
if (c == -1)
break;
}
}
}
}
}
private static Reader throttle(final int sleepBetweenChars, final Reader in) throws IOException
{
final PipedWriter pw = new PipedWriter();
PipedReader pr = new PipedReader(pw);
(new Thread(new Runnable()
{
public void run()
{
System.out.println("Start piping");
int c;
try
{
while ((c = in.read()) != -1)
{
pw.write(c);
Thread.sleep(sleepBetweenChars);
}
pw.close();
System.out.println("Closed PipedWriter");
}
catch (Throwable t)
{
t.printStackTrace();
}
}
})).start();
return pr;
}
}
PipedReader never ready() at end of stream
I agree. That's not what it's for. ready() tells you whether there is data available to be read, not end-of-file conditions. See the Javadoc: ' A piped character stream is ready if the circular buffer is not empty'.
There isn't a way to do what you're trying to do. Streams and Readers are irredemiably blocking. Your code is basically just an elaborate way of implementing blocking yourself, with added latency and added bugs. It's pointless.
I would also question your use of piped readers and writers at all. They are singularly useless things, really only a proof-of-concept for wait() and notify(). Possibly what you're really looking for is a Queue.

What is the least painful way to extract data at the protocol layer in Java?

I'm trying to implement an Android application to connect to the open source software Motion. The goal is to be able to check the status of the application and get the last image captured.
I do not program in Java very much, my background is principally in C and Python. I've not had any real issues with understanding the UI part of Android, but I've found it to be incredibly painful to work with any sort of byte buffer. The Motion software has an HTTP API that is very simple. Opening the URL connection is easy in Java. The response from the default page looks like this
Motion 3.2.12 Running [4] Threads
0
1
2
3
For my purposes the first thing the application needs to do it parse out the number of threads. At some point I can also retrieve the version number from the first line, but that's not really important presently.
Here's my code
package com.hydrogen18.motionsurveillanceviewer;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
public class MotionHttpApi {
String host;
int port = 80;
boolean secure = false;
int numberOfThreads = -1;
String getBaseUrl()
{
StringBuilder sb = new StringBuilder();
sb.append(secure ? "https://" : "http://");
sb.append(host);
sb.append(':');
sb.append(port);
return sb.toString();
}
public int getNumberOfCameras() throws IOException
{
if(numberOfThreads == -1)
{
retrieveSplash();
}
if(numberOfThreads == 1)
{
return 1;
}
return numberOfThreads - 1;
}
void retrieveSplash () throws IOException
{
URL url = new URL(getBaseUrl());
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)
{
throw new IOException("Got response code" + conn.getResponseCode());
}
try{
Byte[] buffer = new Byte[512];
byte[] sbuf = new byte[128];
int offset = 0;
InputStream in = new BufferedInputStream(conn.getInputStream());
boolean foundInfoString= false;
while( ! foundInfoString)
{
//Check to make sure we have not run out of space
if(offset == buffer.length)
{
throw new IOException("Response too large");
}
//Read into the smaller buffer since InputStream
//can't write to a Byte[]
final int result = in.read(sbuf,0,sbuf.length);
//Copy the data into the larger buffer
for(int i = 0; i < result;++i)
{
buffer[offset+i] = sbuf[i];
}
//Add to the offset
offset+=result;
//Wrap the array as a list
List<Byte> list = java.util.Arrays.asList(buffer);
//Find newline character
final int index = list.indexOf((byte) '\n');
//If the newline is present, extract the number of threads
if (index != -1)
{
//Find the number of threads
//Thread number is in the first lin like "[X]"
final int start = list.indexOf((byte)'[');
final int end = list.indexOf((byte)']');
//Sanity check the bounds
if(! (end > start))
{
throw new IOException("Couldn't locate number of threads");
}
//Create a string from the Byte[] array subset
StringBuilder sb = new StringBuilder();
for(int i = start+1; i != end; ++i)
{
final char c = (char) buffer[i].byteValue();
sb.append(c);
}
String numThreadsStr = sb.toString();
//Try and parse the string into a number
try
{
this.numberOfThreads = Integer.valueOf(numThreadsStr);
}catch(NumberFormatException e)
{
throw new IOException("Number of threads is NaN",e);
}
//No more values to extract
foundInfoString = true;
}
//If the InputStream got EOF and the into string has not been found
//Then an error has occurred.
if(result == -1 && ! foundInfoString )
{
throw new IOException("Never got info string");
}
}
}finally
{
//Close the connection
conn.disconnect();
}
}
public MotionHttpApi(String host,int port)
{
this.host = host;
this.port = port;
}
}
The code works just fine when you call getNumberOfCameras(). But I think I must not be really understandings omething in terms of java, because the retrieveSplash method is far too complex. I could do the same thing in just 10 or so lines of C or 1 line of Python. Surely there must be a saner way to manipulate bytes in java?
I think there are some style issues, like I probably should not be throwing IOException whenever the integer fails to parse. But that's a separate issue.
Read the first line as Gautam Tandon suggested and then use a regex.
You can then check if the regex matches and even easily extract the number.
Regex' can be created at http://txt2re.com. I've already done that for you.
The page even creates Java, Pyhton, C, etc. files for you to work with.
// URL that generated this code:
// http://txt2re.com/index-java.php3?s=Motion%203.2.12%20Running%20[4]%20Threads&-7&-19&-5&-20&-1&2&-22&-21&-62&-63&15
import java.util.regex.*;
class Main
{
public static void main(String[] args)
{
String txt="Motion 3.2.12 Running [4] Threads";
String re1="(Motion)"; // Word 1
String re2="( )"; // White Space 1
String re3="(3\\.2\\.12)"; // MMDDYY 1
String re4="( )"; // White Space 2
String re5="(Running)"; // Word 2
String re6="( )"; // White Space 3
String re7="(\\[)"; // Any Single Character 1
String re8="(\\d+)"; // Integer Number 1
String re9="(\\])"; // Any Single Character 2
String re10="( )"; // White Space 4
String re11="((?:[a-z][a-z]+))"; // Word 3
Pattern p = Pattern.compile(re1+re2+re3+re4+re5+re6+re7+re8+re9+re10+re11,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher m = p.matcher(txt);
if (m.find())
{
String word1=m.group(1);
String ws1=m.group(2);
String mmddyy1=m.group(3);
String ws2=m.group(4);
String word2=m.group(5);
String ws3=m.group(6);
String c1=m.group(7);
String int1=m.group(8);
String c2=m.group(9);
String ws4=m.group(10);
String word3=m.group(11);
System.out.print("("+word1.toString()+")"+"("+ws1.toString()+")"+"("+mmddyy1.toString()+")"+"("+ws2.toString()+")"+"("+word2.toString()+")"+"("+ws3.toString()+")"+"("+c1.toString()+")"+"("+int1.toString()+")"+"("+c2.toString()+")"+"("+ws4.toString()+")"+"("+word3.toString()+")"+"\n");
}
}
}
//-----
// This code is for use with Sun's Java VM - see http://java.sun.com/ for downloads.
//
// Paste the code into a new java application or a file called 'Main.java'
//
// Compile and run in Unix using:
// # javac Main.java
// # java Main
//
String int1=m.group(8); gives you the desired integer. Of course you can simplify the above code. It's way to verbose right now.
You can simplify the retrieveSplash method considerably by using BufferedReader. Here's a simpler version of your function:
void retrieveSplash_simpler() throws IOException {
URL url = new URL(getBaseUrl());
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// open the connection
conn.connect();
// create a buffered reader to read the input stream line by line
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// find number of threads
String firstLine = reader.readLine();
int x = firstLine.indexOf("[");
int y = firstLine.indexOf("]");
if (x > 0 && y > 0 && x < y) {
try {
numberOfThreads = Integer.parseInt(firstLine.substring(x+1, y));
} catch (NumberFormatException nfe) {
// disconnect and throw exception
conn.disconnect();
throw new IOException("Couldn't locate number of threads");
}
} else {
// disconnect and throw exception
conn.disconnect();
throw new IOException("Couldn't locate number of threads");
}
// disconnect
conn.disconnect();
}
I'd further clean up the above method by using try/catch/finally blocks at the appropriate places so that I don't have to duplicate that "conn.disconnect()". But I didn't do that here to keep it simple (try/catch/finally do become tricky sometimes...).

Socket, BufferedReader hangs at readLine()

I have a server which initially does this:-
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
for (;;) {
String cmdLine = br.readLine();
if (cmdLine == null || cmdLine.length() == 0)
break;
...
}
later it passes the socket to another class "foo"
This class wait for application specific messages.
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
appCmd=br.readLine();
My client sends this sequence:
"bar\n"
"how are u?\n"
"\n"
"passing it to foo\n"
"\n"
The problem is that sometimes "foo" does not get its response. It hangs in the readLine().
What is the chance that readLine() in the server is buffering up the data using the read ahead and "foo" class is getting starved?
If I add a sleep in the client side, it works. But what is the chance that it will always work?
"bar\n"
"how are u?\n"
"\n"
sleep(1000);
"passing it to foo\n"
"\n"
How to fix the problem? Appreciate any help on this regard.
eee's solution works perfectly. I was trying to read output from an SMTP conversation but it would block on:
while ((response = br.readLine()) != null) {
...Do Stuff
}
Changing to:
while (br.ready()) {
response = br.readLine();
...Do Stuff
}
I can read everything just fine. br is a BufferedReader object, BTW.
There is data already in the first BufferedReader (that has been read from the socket, and is no longer available from the socket), so pass the BufferedReader created in the first example to the class that reads the app specific messages, rather then creating a new BufferedReader from the socket.
I had the same problem and here is my solution:
try {
StringBuilder response = new StringBuilder();
response.append("SERVER -> CLIENT message:").append(CRLF);
//Infinite loop
while (true) {
//Checks wheather the stream is ready
if (in.ready()) {
//Actually read line
lastLineFromServer = in.readLine();
//If we have normal behavior at the end of stream
if (lastLineFromServer != null) {
response
.append(lastLineFromServer)
.append(CRLF);
} else {
return response.toString();
}
} else {//If stream is not ready
//If number of tries is not exceeded
if (numberOfTry < MAX_NUMBER_OF_TRIES) {
numberOfTry++;
//Wait for stream to become ready
Thread.sleep(MAX_DELAY_BEFORE_NEXT_TRY);
} else {//If number of tries is exeeded
//Adds warning that things go weired
response
.append("WARNING \r\n")
.append("Server sends responses not poroperly.\r\n")
.append("Response might be incomplete.")
.append(CRLF);
return response.toString();
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
return "";
}
The answer might be late but this is the simplest and latest answer in 2020, just use the simple way to receive the data from the socket server or client using the input stream read() method.
EOFException will be thrown when the client is disconnected or the server closed the connection.
private String waitForData() throws IOException {
String data = "";
do {
int c = inputStream.read();
if (c > -1) data += (char) c;
else throw new EOFException();
} while (inputStream.available() > 0);
return data;
}

RXTX serial connection - issue with blocking read()

I am trying to use the RXTX library for blocking serial communication on Windows (XP and 7). I have tested the connection with Hyperterminal in both ends, and it works flawlessly.
I set up the connection with the following code: (exception handling and defensive checks omitted for clarity)
private InputStream inStream;
private OutputStream outStream;
private BufferedReader inReader;
private PrintWriter outWriter;
private SerialPort serialPort;
private final String serialPortName;
public StreamComSerial(String serialPortName) {
this.serialPortName = serialPortName;
CommPortIdentifier portIdentifier;
portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortName);
CommPort commPort = null;
commPort = portIdentifier.open(this.getClass().getName(),500);
serialPort = (SerialPort) commPort; serialPort.setSerialPortParams(4800,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
inStream = serialPort.getInputStream();
outStream = serialPort.getOutputStream();
inReader = new BufferedReader(new InputStreamReader(inStream, Settings.getCharset()));
outWriter = new PrintWriter(new OutputStreamWriter(outStream, Settings.getCharset()));
When I use
outWriter.println("test message");
flush();
the message is recieved fine on the other end, but calling
inReader.readLine()
imidiately returns "java.io.IOException: Underlying input stream returned zero bytes".
I then decided to try and implement my own blocking read logic and wrote this:
public String readLine() throws IOException {
String line = new String();
byte[] nextByte = {-1};
while (true) {
nextByte[0] = (byte)inStream.read();
logger.debug("int read: " + nextByte[0]);
if (nextByte[0] == (byte)-1) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
logger.debug("byte read: " + nextByte[0]);
line = line + new String(nextByte);
if (nextByte[0] == (byte)13) { // 13 is carriage return in ASCII
return line;
}
}
}
But this code goes in an infinite loop and "nextByte[0] = (byte)inStream.read();" assigns -1 no matter what is sent over the serial connection. In addition, the other end stutters quite badly and only lets me send a character every 1-3 sec. and hangs for a long time if I try to send many characters in a short burst.
Any help very appreciated.
*edit - using inStream.read(nextByte) instead of "nextByte[0] = (byte)inStream.read();" does not write to the nextByte variable, no matter what I send to it through the serial connection.
*edit2 - as my code works flawlessly with the SUN javax.comm lib and a win32com.dll I got from a friend, I have ceased trying to make it work with RXTX. I am not interested in unblocking communication, which seems to be the only way other people can make RXTX work.
Use RXTX-2.2pre2, previous versions have had a bug which prevented blocking I/O from working correctly.
And do not forget to set port to blocking mode:
serialPort.disableReceiveTimeout();
serialPort.enableReceiveThreshold(1);
I think the code you wrote in your own readLine implementation is buggy. nextByte[0] is never restored to -1 after the first character is read.
You should try to use the value returned by inStream.read(nextByte) to state the number of bytes read from the stream instead of the value of your byte array.
Anyway I think you should go for an event based method of reading the inputs with a SerialPortEventListener:
serialPort.addEventListener(new SerialPortEventListener() {
public void serialEvent(SerialPortEvent evt) {
switch (evt.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE:
dataReceived();
break;
default:
break;
}
}
});
serialPort.notifyOnDataAvailable(true);
it may not be blocking but when the stream is empty, just catch the IOE and keep reading from it. This is what I do with RXTX-2.1-7 and it works fine, I use it to read and write to an arduino:
public static class SerialReader implements Runnable {
InputStream in;
public SerialReader(InputStream in) {
this.in = in;
}
public void run() {
Boolean keepRunning = true;
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while (keepRunning) {
try {
while ((line = br.readLine()) != null) {
//DO YOUR STUFF HERE
}
} catch (IOException e) {
try {
//ignore it, the stream is temporarily empty,RXTX's just whining
Thread.sleep(200);
} catch (InterruptedException ex) {
// something interrupted our sleep, exit ...
keepRunning = false;
}
}
}
}
}
I have solved this way
try
{
if(input.ready()==true)
{
String inputLine=input.readLine();
System.out.println(inputLine);
}
} catch (Exception e)

Categories

Resources