Java socket programming - stream get stuck - java

I am currently working on a simple proxy server, which receives http request from browser, process it, then forward it to the desire web server.
I try to get the request from the input stream of the socket connected by the browser, everything is fine except that the stream get stuck after receiving the last block of data.
My code is in fact very simple, as shown below:
ServerSocket servSocket = new ServerSocket(8282);
Socket workSocket = servSocket.accept();
InputStream inStream = workSocket.getInputStream();
byte[] buffer = new byte[1024];
int numberRead = 0;
while ((numberRead = inStream.read(buffer, 0, 1024)) != -1){
System.out.println(new String(buffer));
}
The loop simply cannot exit, even the request reception is finished.
Is there any method to workaround this problem?
Thanks in advance for any advice.

As in InputStream javadoc the method will block until the data is available or the EOF is encountered. So, the other side of Socket needs to close it - then the inStream.read() call will return.
Another method is to send the size of message you want to read first, so you know ahead how many bytes you have to read. Or you can use BufferedReader to read from socket in line-wise way. BufferedReader has a method readLine() which returns every time a line is read, which should work for you as HTTP protocol packages are nice divided into lines.

It will cycle until the connection is closed, and the client is probably waiting for HTTP response from you and doesn't close it.

The browser is waiting for a response before it closes the connection.
Your read-method on the other hand will block until the stream/connection is closed or new data is received.

Not a direct solution according to your current code.
As HTTP is a line based protocol, you might want to use a Buffered Reader and call readLine() on it.

The when a http request comes in it will always be concluded with a blank line, for example:
GET /someFile.html HTTP/1.1
Host: www.asdf.com
After sending that request the client connection will then wait for a response from the server before closing the connection. So if you want to parse the request from the user you are probably better off using a BufferedReader and reading full lines until you reach a lines of text that is blank line.

Related

BufferedReader.lines().foreach() never terminates

I'm trying to read a HTTP request from a Bufferedreader, that gets Socket.getInputStream() as input. However, when I use Bufferedreader.lines().foreach(), it never terminates and it just gets stuck.
My code (simplified):
Socket socket = new ServerSocket(9090);
Socket newConnection = socket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(newConnection.getInputStream()));
reader.lines().forEach(s -> System.out.println(s));
You need to read more about the HTTP 1.1 protocol. Requests aren't terminated by end of stream. They are terminated by exhausting the byte count in the Content-length header, or of the cumulative chunks if chunked transfer mode is in use. If they were exhausted by end of stream, you could never send a response.
Try creating your socket with parameter-less constructor and use connect() method with port and timeout parameter. This will prevent endless freeze.

How to read the data from datastream

Please help me out on how to read the stream of data in java. My requirement is to make the telnet connection to the router. This part is accomplished. From the router, Have to connect to the xxx remote machine using its ip address and port number through telnet. While making this connection, i am getting some response. But while reading, the program control stops at read() method of InputStream class. Here are the code snippet which i am using to read the stream of data.
buff = new byte[4*1024];
ret_read = 0;
do
{
ret_read = in.read(buff); // Program control gets hanged here. Once all the data are read...
if(ret_read > 0)
{
System.out.println(new String(buff,0,ret_read));
}
}while(ret_read > 0);
What is happening is the read is blocking and waiting for more data to be sent on the stream, it will continue to do that until the stream is closed or more data is sent.
You need to either use a non-blocking read, put a timeout on the read, or close the stream server side after it finishes sending the data.

How do I recognize EOF in Java Sockets?

I want to recognize end of data stream in Java Sockets. When I run the code below, it just stuck and keeps running (it stucks at value 10).
I also want the program to download binary files, but the last byte is always distinct, so I don't know how to stop the while (pragmatically).
String host = "example.com";
String path = "/";
Socket connection = new Socket(host, 80);
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\n\r\n");
out.flush();
int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1)
System.out.println(dataBuffer);
out.close();
Thanks for any hints.
Actually your code is not correct.
In HTTP 1.0 each connection is closed and as a result the client could detect when an input has ended.
In HTTP 1.1 with persistent connections, the underlying TCP connection remains open, so a client can detect when an input ends with 1 of the following 2 ways:
1) The HTTP Server puts a Content-Length header indicating the size of the response. This can be used by the client to understand when the reponse has been fully read.
2)The response is send in Chunked-Encoding meaning that it comes in chunks prefixed with the size of each chunk. The client using this information can construct the response from the chunks received by the server.
You should be using an HTTP Client library since implementing a generic HTTP client is not trivial (at all I may say).
To be specific in your code posted you should have followed one of the above approaches.
Additionally you should read in lines, since HTTP is a line terminated protocol.
I.e. something like:
BufferedReader in =new BufferedReader(new InputStreamReader( Connection.getInputStream() ) );
String s=null;
while ( (s=in.readLine()) != null) {
//Read HTTP header
if (s.isEmpty()) break;//No more headers
}
}
By sending a Connection: close as suggested by khachik, gets the job done (since the closing of the connection helps detect the end of input) but the performance gets worse because for each request you start a new connection.
It depends of course on what you are trying to do (if you care or not)
You should use existing libraries for HTTP. See here.
Your code works as expected. The server doesn't close the connection, and dataBuffer never becomes -1. This happens because connections are kept alive in HTTP 1.1 by default. Use HTTP 1.0, or put Connection: close header in your request.
For example:
out.write("GET "+ path +" HTTP/1.1\r\nHost: "+ host +"\r\nConnection: close\r\n\r\n");
out.flush();
int dataBuffer;
while ((dataBuffer = connection.getInputStream().read()) != -1)
System.out.print((char)dataBuffer);
out.close();

Unable to close http streaming on wrong response

My apache HTTP client is reading data from a server which is sending HTTP streaming (in form of chunked data) to us.
I have a input stream and Buffered Reader to get data, and reading this data using Buffered Data readLine method.
InputStream inputStream = httpEntity.getContent();
br= new BufferedReader(new InputStreamReader(inputStream));
while ((line = br.readLine()) != null)
I want to close the connection if I get a wrong response from server.
For this I am creating a timertask at a time interval to close my connection.
I am parsing the response each time I receive it to check if the response is correct, if the response is correct then I reset the timetask. If I find a wrong response in that case I don't reset the timertask (and let the timertask be executed to the time it was previously set for)
I want to know if using unbuffered I/O can help? or I need some other approach?
Problem I see is since the connection is open, my timertask is unable to close the connection. inputStream.close or bufferReader.close both are not able to execute (seem to infinitely wait)
BufferReader.close() will only close the inputStream, which in turn will call inputStream.close(). According to the java api InputStream.close() does nothing. You need to close the socket, or whatever it is that you are abstracting by httpEntity.

Why is the end of the input stream never reached using Java Sockets?

I am writing a simple proxy in Java. I am having trouble reading the entirety of a given request into a byte array. Specifically, in the following loop, the call to 'read' blocks even though the client has sent all the data that it will (that is, the end of stream is never reached). As I can't be sure that it is time to start writing output until I've read the entirety of the input, this is causing a bit of trouble. If I kill the connection to the server, the end of stream is finally reached, and everything goes off without a hitch (all of the data from the client, in this case Firefox requesting www.google.com, has been read by the server, and it is able to process it as required, though obviously it can't send anything back to the client).
public static void copyStream(InputStream is, OutputStream os) throws IOException
{
int read = 0;
byte[] buffer = new byte[BUFFER_SIZE];
while((read = is.read(buffer, 0, BUFFER_SIZE)) != -1)
{
os.write(buffer, 0, read);
}
return;
}
The InputStream comes from the client socket (getInputStream(), then buffered) directly; the OutputStream is a ByteArrayOutputStream.
What am I doing wrong?
Typically in HTTP the Content-Length header indicates how much data you're supposed to read from the stream. Basically it tells you how many bytes follow the double-newline (actually double-\r\n) that indicates the end of the HTTP headers. See W3C for more info...
If there is no Content-Length header sent, you could try interrupting the read after a certain amount of time passes with no data sent over the connection, although that's definitely not preferable.
(I'm assuming that you're going to be processing the data you're reading somehow, otherwise you could just write out each byte as you read it)
HTTP 1.1, supported by all modern browsers, has a feature called "keep-alive", or "persistent connections", in which clients are allowed by default to reuse a HTTP 1.1 connection to a server for several requests (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html).
So if you are pointing FF to http://www.google.com, the connection to www.google.com:80 will remain open for a while, even if the first request has been completed. You thus can not know if all the data has been sent without a basic understanding of HTTP protocol by your application.
You can somehow circumvent that by using a timeout on the connection, hoping the client is not stuck somewhere and that silence actually means the end of the data block.
An other way would be to rewrite server response headers, to advertise your proxy as HTTP 1.0 compliant, and not 1.1, thus forbidding the client to use persistent connections.
Keep in mind that not all connections will have a Content-Length header; some may be using Transfer-Encoding: chunked where the content length is encoded and included as part of the body.

Categories

Resources