How to detect FIN - tcp flag in java application? - java

I have long-lasting TCP connection between two computers (second not under my control). Second computer can send FIN flag at every moment, and first must close connection corrent (send FIN flag back to second computer).
How can I know that the second computer sending a FIN flag and when I must cause socket.close() method of my Java application?

Normally, you have to read the connection and when this returns -1 for EOF or an appropriate IOException, you can close the connection. Note: SocketTimeoutException doesn't mean the connection is closed.
an example.
boolean ok = false;
try {
int b = in.read();
ok = b >= 0;
if (!ok)
throw new EOFException();
} finally {
if (!ok)
in.close();
}

Detecting a soft connection close by the other side (when they manage to send FIN/RST flags) is only partially possible with the old Java I/O library. You will learn of a broken connection only via a timeout, so it may be far from immediate. Your threads may hang for a long time before they realize that the party at the other end is long gone.
In order to handle it better, you need to use nio. There, such a situation will be recognized by the Selector saying there is data ready for reading but then read on the channel returning less than zero. This will allow you to learn about soft connection resets almost immediately.
On the other hand, a hard connection termination (e.g. someone cutting the wire or network being down) can only be detected via timeouts regardless of which libraries you use as it's a property of the TCP protocol itself.

As explained above, the Socket's properties (isClosed, isConnected, etc) are not helpful. A proper solution would be to set a reasonable SO_TIMEOUT and read from the socket:
In case of connection closed by the peer, the read operation would return with '-1'
In case of read timeout, the read operation would throw SocketTimeoutException.
(Scala code)
val socket = new Socket("localhost", 8888)
socket.setSoTimeout(10000) /* Set reasonable read timeout */
try {
val res = socket.getInputStream().read()
if (res < 0)
... /* Socket closed */
else
... /* Socket read succeeded */
} catch {
case _: SocketTimeoutException => ... /* Socket not closed */
case _ => ... /* Merde */
}

Related

Slow tcp connection causes my app to stall

I have found a class that handles TCP connections and I am using it to communicate with a gaming service. All was working fine until I realized that my application was stalling if the connection speed was slower. I have a thread polling let's say every 30 seconds.
I got the TCPClient class I use from this thread Java TCP sending first message, then infinite wait
This service requires 2 steps to verify a request. You first send a hash and you receive and acknowledge. Then you send the the actual request and you receive the response.
public byte[] getResponse(byte[] hash, byte[] request) throws Exception{
if(client == null || client.socket.isClosed() || !client.socket.isConnected()
|| client.socket.isInputShutdown() || client.socket.isOutputShutdown(){
client = new TCPClient(this.host, this.port);
}
client.SendToServer(hash);
byte[] ack = client.ReceiveFromServer();
if(checkAck(ack, getAckForRequest(request))){
client.SendToServer(request);
byte[] response = client.ReceiveFromServer();
return response;
}
}
My code looks something like this. I simplified it a bit to make it more readable.
I am using this function inside a try/catch block and when it throws an exception I store the request in a MySQL database.
Is there a way to avoid blocking my main thread if the connection is slow and do the same stuff?
Is there a way to avoid blocking my main thread if the connection is slow and do the same stuff?
Yes. One can call setSoTimeout() on a Socket.
The Oracle documentation:
https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setSoTimeout-int-
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.
If you just want to close the connection and give up it works well. If you want to resume the action later you have to keep track of the bytes already read which means just having more threads is usually an easier option.

Java Socket returns EOF on low bandwidth

I'm making an Android app for playing online radio. I'm using Java Socket for connection and it's InputStream to read stream data. Actually there is HTTP request and response without length with content type such as audio/mpeg.
All works fine until bandwidth becomes low (using mobile internet or connected to slow/very remote server) - InputStream may return EOF (-1) at arbitrary time.
Please could you explain the nature of such behavior and possible ways to deal with it. I set read timeout (Socket.setSoTimeout), so why it doesn't throw timeout exception if the case is low bandwidth? Maybe there are another socket options that may help?
That happens when you have Client connected and then It disconnects and you are trying to read from it. I handle this asking the length of the message, If it is negative, I restart the connection.
E.G.
//CLIENTS LOOP
while (true)
{
...
//MESSAGE LOOP
while ( true )
{
System.out.println(" -> WAITING FOR INCOMING MESSAGE.. ");
len = inputStream.read(buffer_msg);
if ( len < 0 )
break;
...

What happens to data received by a socket in case of timeout exception during readShort()?

I'm developing a client (Java)/server(C++) application using TCP sockets.
The protocol I used is composed of Messages beginning by 2 bytes defining the type of what will be the content of the Message.
So basically, the receiving thread waits for data to be received in a loop. But I want to use a timeout with the socket to be notified that the other host takes too long to send data.
receivingSocket.setSoTimeout(durationInMilliseconds);
DataInputStream in = new DataInputStream(receivingSocket.getInputStream());
boolean success = false;
short value = 0;
do {
try {
value = in.readShort();// will throw a SocketTimeoutException in case of timeout, without 2 bytes available from the socket
success = true;
} catch (SocketTimeoutException e) {
/// do something if it happens to often. Otherwise go on with the loop
}
} catch (IOException e) {
/// abort connection in case of other problem
}
} while (!success)
Now, what happens if the receiving thread calls in.readShort() at a point where the socket has got only one byte available in its buffer ? Does this byte remain on the socket's stack ? Or is it lost ? In the first case, I could read it next time I call in.readShort(), otherwise it seems lost for good...
readShort() here is an example, my question stands also for readInt(), ...
Thanks for your help,
It isn't specified. I believe the way the implementation works is that the half data is lost, but in any case there's nothing written that says anything else, so you just have to assume the worst.
However in practice this is very unlikely to happen, provided you observe common sense at the sender.

apr_socket_recv: An established connection was aborted by the software in your host machine

I'm creating a small server using java.nio, but when trying to stress test it I keep getting messages about the connection being reset on the server side, or more specifically:
apr_socket_recv: An established connection was aborted by the software in your host machine
I've tried to narrow it down to the most simple of loops, but still no luck. I can get the error after a hundred or so connections, or maybe just after 1 or 2.
Here's the server loop:
byte[] response = ("HTTP/1.1 200 OK\r\n"
+ "Server: TestServer\r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n"
+ "<html><b>Hello</b></html>").getBytes();
SocketChannel newChannel = null;
while (active) {
try {
//get a new connection and delegate it.
System.out.print("Waiting for connection..");
newChannel = serverSocketChannel.accept();
System.out.println("ok");
newChannel.configureBlocking(true);
newChannel.write(ByteBuffer.wrap(response));
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
newChannel.close();
} catch (IOException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I've tried checking if the write didn't write all requested byte, but it seemingly does. Interestingly enough, calling System.gc() after each newChannel.close() makes the problem disappear (but in return, it's horribly slow). So either I'm not releasing all resources I should release, or the application just needs a pause..
I'm losing all of my best years on this. Oh, and by the way.. if I ignore writing to the channel and just close after I accept the connection, the problem still doesn't go away.
Well I found it out, so I might as well share it.
My app needed a pause. It was simply going too fast, and closing the connection before the client had written all of its request data. The fix would be to keep on reading until the entire HTTP request had been received. D'oh.. lesson learned.
From the docs for SocketChannel#Write (emphasis mine):
An attempt is made to write up to r bytes to the channel, where r is
the number of bytes remaining in the buffer, that is, src.remaining(),
at the moment this method is invoked.
[...]
Returns: The number of bytes written, possibly zero.
It's up to you to check the return value from the write call (which you're not doing presently), and issue successive write calls until the whole of the buffer has been sent. Something like this, I guess:
ByteBuffer toWrite = ByteBuffer.wrap(response);
while (toWrite.remaining() > 0) {
newChannel.write(toWrite);
}
You'll obviously get aborts if you don't write all of your response data and then just close the socket.

How to timeout a read on Java Socket?

I'm trying to read items from a socket and I notice that if there is nothing on the stream of the socket it will stay at the read and back up my application. I wanted to know if there was a way to set a read timeout or terminate the connection after a certain amount of time of nothing in the socket.
If you write Java, learning to navigate the API documentation is helpful. In the case of a socket read, you can set the timeout option, e.g.:
socket.setSoTimeout(500);
This will cause the InputStream associated with the socket to throw a SocketTimeoutException after a read() call blocks for one-half second. It's important to note that SocketTimeoutException is unique among exceptions thrown by such read() calls, because the socket is still valid; you can continue to use it. The exception is only a mechanism to escape from the read and decide if it's time to do something different.
while (true) {
int n;
try {
n = input.read(buffer);
catch (SocketTimeoutException ex) {
/* Test if this action has been cancelled */
if (Thread.interrupted()) throw new InterruptedIOException();
}
/* Handle input... */
}
If this socket was created through a URLConnection to perform a web request, you can set the read and connect timeouts directly on the URLConnection before reading the stream:
InputStream createInputStreamForUriString(String uriString) throws IOException, URISyntaxException {
URLConnection in = new URL(uriString).openConnection();
in.setConnectTimeout(5000);
in.setReadTimeout(5000);
in.setAllowUserInteraction(false);
in.setDoInput(true);
in.setDoOutput(false);
return in.getInputStream();
}
Yes, there should be an override of Read() that accepts a timeout value. By 'override' I am not suggesting anyone write one, I am pointing out that one of the overrides of the socket methods he is using takes a timeout value.

Categories

Resources