BufferedReader.lines().foreach() never terminates - java

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.

Related

DataInputStream stuck when initialized

I have been trying to send a byte[] array across my client / server application using Sockets, DataInputStream and DataOutputStream, but on the server side, the program just gets stuck when I try to initialise the DataInputStream.
Here is the code on the client side (it works fine):
DataOutputStream datas = new DataOutputStream(connection.getOutputStream());
datas.flush();
byte[] send = identityKeyPair.serialize();
datas.write(send);
datas.flush();
Here is the code on the server side:
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()) );
sender = new PrintWriter(connection.getOutputStream());
newUser = new BasicUserData();
System.out.println("New registration from: " + connection.getInetAddress());
System.out.println("Data:");
String un = reader.readLine();
newUser.USERNAME = un;
System.out.println(newUser.USERNAME);
String pw = reader.readLine();
newUser.PASSWORD = pw;
System.out.println(newUser.PASSWORD);
DataOutputStream dataout = new DataOutputStream(connection.getOutputStream());
System.out.println("Opened data output stream");
DataInputStream receiver = new DataInputStream(connection.getInputStream());
//It gets stuck here, and the program doesn't read anything further
receiver.read();
byte[] id = receiver.readAllBytes();
System.out.println("Opened data input stream");
You are using both connection.getInputStream() and connection.getOutputStream() in two different ways. You should use one and only one way of reading from and writing to streams, don't mix multiple ways.
When you execute reader.readLine(), the BufferedReader called reader will read up-to 8192 characters from the input stream into its buffer, likely consuming all bytes your client has written. This means that when you construct your DataInputStream around that same input stream and try to read it, there is no data available to read, causing the receiver.read() to block waiting for data. That data is never received as your client has sent all its data, which is now buffered in reader.
In addition, unless your client has closed its output stream, InputStream.readAllBytes() will block indefinitely anyway, because it is only finished when the end-of-stream has been reached. And for socket communication, that only happens when the other side closed its output stream.
Change your code so there is only one way of writing data (though not relevant here), and one way of reading data. In addition, you should establish clearly how you need to read and write data in a protocol, so to avoid consuming too much data at the wrong point, and to know how much data you need to read when.
Of course it does nothing but wait as specified in the javadoc a call to DataInputStream#read() blocks the current thread until data can be read from the input stream.
Your reader = BufferedReader(...) uses the same underlying InputStream which means the all the data the client sent is most likely already consumed by the 'login' logic.
Since neither the client nor the server close their respective streams no EOF is emitted either which leads to the stream 'just dangling' around waiting for more data.
Unless your client sends more data the server will wait eternally.
There are two solutions for your issue.
Either thread you application so that the 'await input' logic is in it's own thread or take a look at javas NIO package (more precisely Channels and Selectors)

Java SSLSocket Outputstream message breaks

I have a problem, where a message I write to the OutputStream of a SSLSocket is send in multiple parts instead of one packet.
So, I have a SSLSocket:
final Socket newSocket = SSLSocketFactory.getDefault ().createSocket (server, port);
Since I connect to a special service, I manually send a non HTTP-standard connect header, which works just fine:
final OutputStream outputStream = newSocket.getOutputStream ();
outputStream.write (connect.getBytes ());
outputStream.flush ();
newSocket.setKeepAlive (true);
I then wait for a response, until I get a newline in it:
final InputStream inputStream = newSocket.getInputStream ();
final InputStreamReader inputStreamReader = new InputStreamReader (inputStream, "ISO-8859-1");
final BufferedReader bufferedReader = new BufferedReader (inputStreamReader);
I finish reading when I received a HTTP/1.1 200 Ok in a loop reading from the BufferedReader. Again, until this point everything is fine.
Then I begin using this socket to send messages from my own protocol like this:
outputStream.write (message.getBytes ());
outputStream.flush ();
When I now run a tcpdump on the target device, I can see that the socket connection is established and in fact two packets are send. Assuming the message would be Hello World, there is one packet which is marked as malformed, only containing the H. Then another one follows with the content ello World. No Exception is thrown during the run of this program.
Would could I possibly have done or missed to cause this kind of behaviour?
There are reasons for that I can not give you the complete code, but this question already contains all the significant passages.
Update:
As proposed in the comments, I tried to disable the Nagle algorithm using newSocket.setTcpNoDelay(true); just after creating the socket. But still, the packets sent are fragmented.

Does a Socket InputStream read() unblock if server times out?

I have a server that times out after 45 seconds if it hasn't received a full request and closes the connection. I connect to this server through a Socket and write my request to the socket's OutputStream.
Socket socket = new Socket("myhost", myPort);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.write(properRequestMessage);
out.flush();
I'm assuming here that my request is good (follows my protocol). The server is supposed to respond with a file. I try to read from the socket inputstream:
BufferedReader response = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String in;
while((in = response.readLine()) != null) {
System.out.println(in);
}
The readLine() blocks here and I think it is because my server thinks my request isn't properly terminated and is therefore waiting for more.
Now, if 45 seconds pass and my server times out, will the readLine() unblock or wait for some Socket default timeout time?
That depends on what the server does when it times out. If it closes the connection you will see that. If it just logs a message, you might not see anything.
There is no default read timeout. Your readLine() can wait forever.
If the server closes its end of the socket on that timeout, then readLine() will return null.
The readLine() method will block until it receives an input or until the underlying socket read() timeout ends.
You don't set the timeout on the read command but rather on the socket it self.
Socket.setSoTimeout(int ms).
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
What actually occurs also depends on what the server does, if it closes the socket correctly a IOException should be thrown by readLine(). If the connection isn't close it will wait for the socket to timeout.

Setting a time-out limit to readLine()?

I have the following code that reads response from a POP server through Sockets in Java. But the problem is sometimes, when I use the readLine() function to read from the server and if the server does not reply with any response, my application will hang there, waiting for a response from the server.
socket.connect(new InetSocketAddress("pop.server.com", 110), 3000);
input = socket.getInputStream();
BufferedReader incoming = new BufferedReader(new InputStreamReader(input));
incoming.readLine(); //This line will cause my application to hang if the server does not respond with a reply
Is there a way to set a timeout or some other ways that when the server does not reply after a certain amount of time, the application should stop waiting for a response and continue its other execution?
I suggest you try Socket.setSoTime(timeout)

Java socket programming - stream get stuck

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.

Categories

Resources