Java InputStream blocking read

2019-01-04 07:42发布

According to the java api, the InputStream.read() is described as:

If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

I have a while(true) loop doing a read and I always get -1 when nothing's sent over the stream. That's expected.

My question is when would read() ever block? Since if it doesn't get any data it returns -1. I would expect a blocking read to wait until data is received. If you've reached the end of the input stream, shouldn't read() simply wait for data instead of returning -1?

Or does read() only block if there's another thread accessing the stream and your read() cannot access the stream?


Which leads me to my next question. I used to have event listener (provided by my library) that would notify me when data is available. When I was notified I would call while((aByte = read()) > -1) store the byte. I was puzzled when I'd get TWO events in very close time proximity and not all my data was being displayed. It seemed like only the tail end of the second event's data would be displayed and the the rest was missing.

I eventually changed my code so that when I get an event I'd called if(inputStream.available() > 0) while((aByte = read()) > -1) store the byte. Now it worked properly and all my data was displayed.

Can someone explain this behavior? The InputStream.available() is said to return the number of bytes you can read before blocking the next caller (of the stream?). Even if I don't use .available() I would expect the read of the first event to just block the read of the second event, but not erase or consume too much stream data. Why would doing this cause not all of my data to be displayed?

8条回答
闹够了就滚
2楼-- · 2019-01-04 07:45

It returns -1 if it's end of stream. If stream is still open (i.e. socket connection) but no data has reached the reading side (server is slow, networks is slow,...) the read() blocks.

You don't need call available(). I have a hard time understanding your notification design, but you don't need any calls except read() itself. Method available() is there for convenience only.

查看更多
唯我独甜
3楼-- · 2019-01-04 07:45

InputStream is just an abstract class, unfortunately the implementation decides what happens.

What happens if nothing is found:

  • Sockets (i.e. SocketInputStream) will block until data is received (by default). But it's possible to set a timeout (see: setSoTimeout), then the read will block for x ms. If still nothing is received then a SocketTimeoutException will be thrown.

    But with or without timeout, reading from a SocketInputStream can sometimes result in a -1. (E.g. when multiple clients simultaneously connect to the same host:port, then even though the devices seem connected, the result of a read could immediately restult in a -1 (never returning data).)

  • Serialio communication will always return -1; You can also set a timeout (use setTimeoutRx), the read will first block for x ms, but the result will still be -1 if nothing's found. (Remark: but there are multiple serial io classes available, behaviour could be vendor dependent.)

  • Files (readers or streams) will result in an EOFException.

Work to a Generic Solution:

  • If you wrap any of the above streams in a DataInputStream, then you can use methods like readByte, readChar, etc . All -1 values are converted to EOFException. (PS: If you perform a lot of small reads, then it's a good idea to wrap it in a BufferedInputStream first)
  • Both SocketTimeoutException and EOFException extend IOException , and there are several other possible IOException's. It is convenient to just check for IOException's to detect communication issues.

Another sensitive topic is flushing. flush in terms of sockets means "send it now", but in terms of Serialio it means "discard the buffer".

查看更多
虎瘦雄心在
4楼-- · 2019-01-04 07:51

The underlying data source for some implementations of InputStream can signal that the end of the stream has been reached, and no more data will be sent. Until this signal is received, read operations on such a stream can block.

For example, an InputStream from a Socket socket will block, rather than returning EOF, until a TCP packet with the FIN flag set is received. When EOF is received from such a stream, you can be assured that all data sent on that socket has been reliably received, and you won't be able to read any more data. (If a blocking read results in an exception, on the other hand, some data may have been lost.)

Other streams, like those from a raw file or serial port, may lack a similar format or protocol to indicate that no more data will be available. Such streams can immediately return EOF (-1) rather than blocking when no data are currently available. In the absence of such a format or protocol, however, you can't be sure when the other side is done sending data.


With regard to your second question, it sounds like you may have had a race condition. Without seeing the code in question, I'm guessing that the problem actually lay in your method of "display". Perhaps the attempt to display by the second notification was somehow clobbering the work done during the first notification.

查看更多
小情绪 Triste *
5楼-- · 2019-01-04 07:53

I am using eclipse Jetty 9.2.2. I am surprised to see that 10-12% of my request are taking around 500+ mili-seconds each while others get processed within 2-3 mili-seconds each. portion of the code taking

timeBufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));

String line = null;
String postData = "";
while ((line = br.readLine()) != null){ // this is the line taking all time
    postData+=line;
}

br.close();
查看更多
Root(大扎)
6楼-- · 2019-01-04 07:57

By default the behavior of the provided RXTX InputStream is not compliant.

You have to set the receive threshold to 1 and disable the receive timeout:

serialPort.enableReceiveThreshold(1);
serialPort.disableReceiveTimeout();

Source: RXTX serial connection - issue with blocking read()

查看更多
劫难
7楼-- · 2019-01-04 07:58

I think You can receive the entire data stream if you use thread.sleep()

查看更多
登录 后发表回答