As a challenge I have implemented a basic web server in Java. When I open the raw InputStream I immediately go into a blocking read which reads the entire 400 or bytes of the HTTP request into a byte array. This works, however I then do not check for any more data and simply close the socket after sending a response.
I’m wondering is there a more robust way to do this so as not to miss any data from the client. I thought of reading one byte at a time until read returned end of stream. However it instead sometimes blocks when there is no more data and confusingly the JavaDocs for public abtract int InputStream.read() says:
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.
So it implies that two things can happen if the end of stream is reached: returning -1 and blocking. I am seeing blocking.
My question is, with a protocol like HTTP, how should you read from the socket and how do you know when that’s all the data you’ll be getting in this connection?
The JavaDoc you quote does not imply that two things can happen if the end of stream is reached. It doesn’t say read blocks when the end of the stream is detected, but until the end of stream is detected. Once it is detected, -1 is returned.
This explains the behavior you’re observing: no end of stream is detected and read is blocked. The end of stream is detected once the connection is closed, but it isn’t closed since the client doesn’t close the connection immediately after sending a request. It must keep it open to receive the reply.
In order to ensure you receive all data from the client you should parse their HTTP request until you see the end of header (double newline) plus whatever amount of data they have specified in the header (if any).
If you’d like to avoid blocking have a look at
java.nioand channels (SocketChannelin particular).