-1

I wrote a HttpServer, here is the code snippet:

the code snippet

As the snapshot marked, it can't work:

the address bar

This is the result when I visit the HttpServer by browser:

the output

I do not know what causes it, anybody could help me?

Thanks

Rocky Hu
  • 1,326
  • 4
  • 17
  • 32
  • An `InputStream` is supposed to return `-1` when no more data is available, I thought... – awksp May 17 '14 at 05:17
  • But why it didn't return -1? – Rocky Hu May 17 '14 at 05:22
  • I don't know? Seems to me that it should... Does the output repeat infinitely or something? – awksp May 17 '14 at 05:23
  • No,I think read from NetWork isn't similar to that from File, when I read from File,it always can return -1 when the end of the stream is reached, but form Network, it seems like can't judge whether haven been reached the end or not. – Rocky Hu May 17 '14 at 05:28
  • So what does your code print? – awksp May 17 '14 at 05:28
  • Couldn't return anything to browser, and the console's result is the third pics that I posted. – Rocky Hu May 17 '14 at 05:30
  • What do you mean by return anything to browser? And my mistake, I initially thought the numbers were what the browser was displaying. – awksp May 17 '14 at 05:31
  • What happens if you close your browser. Do you read a -1 then? – codenheim May 17 '14 at 05:54

2 Answers2

2

No, an InputStream will return -1 when the socket is closed. End of stream means "End of File" ie. closed connection. It doesn't mean "no data read".

The socket is likely still open, so your code is blocking for the next request and never returning a -1. It will not return until either more data arrives, or the stream is closed.

The request is probably an HTTP 1.1 request. With HTTP 1.1, the socket will stay open to allow reuse of the connection, unless your server decides not to honor it, or the web browser decides to close it. The point of HTTP 1.1 is to allow multiple HTTP requests to pipeline on a single TCP stream connection, and avoid the overhead of build/teardown.

A socket can stay open, but idle with no data for a long time, so if you try to read from it with a blocking call, your code will hang. The Java InputStream.read() call will block, because it cannot return 0, since 0 is a valid byte value. I recommend that you switch to an alternate read() form, in any case.

Finally, if you are going to write an HTTP server, you shouldn't be using end of stream as your only method of managing the incoming request, you need to parse or scan the request for a legally formed HTTP request, and once received, serve a response, then close the connection. As it is, your current approach doesn't know if/when the HTTP response is well-formed or complete.

Refer to online RFC of the HTTP protocol for the format of a legal request. Request lines end in CR-LF (carriage return + linefeed). You read the 1st line as the request (command), and then a single empty line (CR-LF only), then any HTTP headers will be 1 per line, and when you receive the next empty line, it is the end of the request. You should at minimum issue a "Connection: close" header if you intend to close the socket. Otherwise the client may think your server can handle pipelined requests.

http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

codenheim
  • 20,467
  • 1
  • 59
  • 80
  • And that's the reason the `InputStream` wasn't behaving as I thought it would. Is there no way to differentiate between a 0 as part of data and 0 as in no more data then? – awksp May 17 '14 at 05:32
  • But could it be possible to have a 0 in the data? And if that were the case why doesn't OP's code print 0s at the end? – awksp May 17 '14 at 05:34
  • 0 byte (0x00) is different than "0" ASCII. An HTTP server needs to handle any byte value, regardless, but in this case, it appears he is dealing with standard ASCII text. – codenheim May 17 '14 at 05:37
  • `InputStreams` read bytes, though... And `data` is an `int`. Where does ASCII text come into play here? – awksp May 17 '14 at 05:38
  • You are right, I misread, he is using the zero argument form of read(), I thought he was using the read(byte[]) form. So yes, he printing the int values. – codenheim May 17 '14 at 05:45
  • Yep, that answer makes sense to me, and if there were something wrong I don't know enough to say so. +1. – awksp May 17 '14 at 05:57
  • Thanks. I answered hastily, assuming he was using a non-blocking read. But in Java, InputStream.read() (zero arguments) blocks. It isn't the best approach for network coding, non-blocking is preferred. – codenheim May 17 '14 at 06:02
  • Google shows stuff related to [SocketChannel](http://docs.oracle.com/javase/8/docs/api/java/nio/channels/SocketChannel.html) might work... Do you know if these would be preferable to an `InputStream`? – awksp May 17 '14 at 06:04
  • It is ok to use a blocking read if you spin off a thread to do it on. Otherwise, yes, I think you need to switch to SocketChannel or Socket (if I recall..). Sorry, coding socket stuff in too many languages over the years, it is running together now with age. In Java, threads are easy enough, I would probably just try blocking read in a worker thread per connection. – codenheim May 17 '14 at 06:10
  • Good point. Might be interesting to decide what to do if the reading thread never returns (maybe kill it after a while?), sounds like a reasonable alternative. Maybe put that in your answer? And no need to apologize, learning new things is always nice. – awksp May 17 '14 at 06:15
  • @EJP is right. I'm so darned rusty, my memory failed me. I'm not sure where I got 0 from, maybe it is my memory of select() call when polling descriptor sets, but even that may not be. I should probably not answer something I haven't done in years. Oddly I used to code sockets on a daily basis. All the W. Richard Steven's books on my shelf, and I answered with some embarassing nonsense. Sorry guys. – codenheim May 17 '14 at 07:14
  • I removed the sentence about the imaginary 0 return value that I conjured from nowhere. – codenheim May 17 '14 at 07:17
  • `InputStream.read()` is blocking, period, and cannot return zero at all, other than the no-arg form, which can do so any time a `NUL` occurs in the input. `SocketChannel.read()` can be non-blocking, and return zero, but he isn't using it. – user207421 May 17 '14 at 07:19
  • Yes, I originally saw his question, realized his problem was probably misunderstanding of End Of Stream, but should have limited my answer to that since I don't know the Java network API from memory (and apparently no longer know the Berkeley API either!) – codenheim May 17 '14 at 07:24
1

It doesn't make sense to read the input until EOS and then expect to be able to write a response back to the same connection.

You haven't actually written anything like an 'simple HTTP server yet. You need to study the HTTP RFC, in particular the part about content-length of requests. They are delimited by length, not by end of stream.

user207421
  • 305,947
  • 44
  • 307
  • 483