Is java.net.Socket.setSoTimeout reliable? - java

From the JavaDoc for setSoTimeout
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.
From the variety of posts on the Internet I have read that SO_TIMEOUT is rather unreliable when using Socket C API ( e.g. here ).
Hence the question, is it reliable to use setSoTimeout to check for run-away sessions?
If not, what techniques can you recommend to put a time limit on socket sessions?

I don't know any relevant recent/current operating system, on which (stream) socket timeouts are not working as they are supposed to. The post you're linking to is from a rather confused poster, which is trying to set a send timeout on a datagram socket, which makes absolutely no sense. Datagrams are either sent immediately or silently discarded.

I am not aware of any modern platform OS platform whose network stack is so broken that socket timeouts don't work. But if anyone knows of a real life example, please add it as a comment!
I would not worry about this scenario unless you are actually forced to support your application on such a broken OS. I suspect that it would be a painful exercise.

The link is about SO_RCVTIMEO. The question is about Socket.setSoTimeout(). In the only platform I am aware of where the former doesn't work (some versions of Solaris), the latter is fudged up using select(), which does work. The contract of the method demands it. You don't need to worry about this unless someone actually comes up with a platform where it doesn't I've never seen one in 16 years.

Check out the connectivity classes in Java 6 nio, they include sockets now and do non-blocking operation so you can cancel an operation if you want to.
Apache htmlclient core (?) is now able to use the nio sockets, so it seems they got that concept working. That's all I know about it, though.

Related

Why SSLSocket write option does not have timeout?

In Java, write operation on SSLSocket API is blocking and the write operation does not support timeout also.
Can someone please explain?
Can there be a situation where write operation can block a thread forever? I checked on Internet and it seems that there is a possibility of blocking forever.
How to add timeout for write operation?
My application creates two threads one for read and one for write.
1- Can there be a situation where write operation can block a thread forever? I checked on Internet and it seems that there is a possibility of blocking forever.
Yes there can. Though not literally forever :-)
2- Can someone please suggest how we can add timeout for write operation?
You cannot do it with Java's implementation of sockets / SSL sockets, etcetera. Java sockets support connect timeouts and read timeouts but not write timeouts.
See also: How can I set Socket write timout in java?
(Why? Well socket write timeouts were requested in bug ID JDK-4031100 back in 1997 but the bug was closed with status "WontFix". Read the link for the details.)
The alternatives include:
Use a Timer to implement the timeout, and interrupt the thread or close the Socket if the timer goes off. Note that both interrupting and closing will leave you in a state where you need to abandon the socket.
Use NIO selectors and non-blocking I/O.
Because:
If such a facility is needed at all, it is needed at the TCP level, not just the SSL level.
There is no API for it at the TCP level, and I don't mean just in Java: there is no C level API for it either, except maybe on a couple of platforms.
If you added it at the SSL level, a write timeout event would leave the connection in an indeterminate state which would mean that it had to be closed, because you couldn't know how much data had been transmitted, so you couldn't maintain integrity at the SSL level.
To address your specific questions:
Can there be a situation where write operation can block a thread forever? I checked on Internet and it seems that there is a possibility of blocking forever.
Yes. I've seen an application blocked for several days in such a situation. Although not, as #StephenC rightly says, forever. We haven't lived that long yet.
How to add timeout for write operation?
You can do it at the TCP level with non-blocking I/O and a Selector, and you can layer an SSLEngine on top of that to get SSL, but it is a tedious and highly error-prone exercise that many have tried: few have succeeded. Not for the faint-hearted.

What is the current method for server/client network connections

I haven't used Java for along time. Googling seems to bring up a lot of different methods.
What is the current, modern, accepted method for TCP socket connections these days? I don't want to implement something that is going to become deprecated soon.
If it matters, I will be sending JSON bidirectionally between client and server and would like non-blocking sending and receiving and blocking initial connections.
From what I can see, ServerSocketChannel looks pretty recent (I hadn't heard about it until now)...is that what I should be using?
What is the current, modern, accepted method for TCP socket connections these days?
You can use Netty or Mina, but I would use just Plain IO and perhaps blocking NIO as I believe these are the simplest. All of these have been around about ten years or more.
I don't want to implement something that is going to become deprecated soon.
I can't think of the last time anything was truly deprecated in Java.
ServerSocketChannel looks pretty recent
It was added in Java 1.4 in 2002. ;)
Despite what most sites will suggest, I believe blocking NIO is simpler to work with (and it can be faster for a small number of connections)
If all you want to do is send and receive JSON text, I would use Plain IO. I would use an ExecutorService to manage the threads you need to support this. These were added in 2004, but are actually much older.

Does Windows interfere with Java's Socket.setSOTimeout?

I am reading here, that
On connect, the JVM (Java Virtual Machine) tries to resolve the
hostname to IP/port. Windows tries a netbios ns query on UDP (User
Datagram Protocol) port 137 with a timeout of 1.5 seconds, ignores any
ICMP (Internet Control Message Protocol) port unreachable packets and
repeats this two more times, adding up to a value of 4.5 seconds. I
suggest putting critical hostnames in your HOSTS file to make sure
they are resolved quickly. Another possibility is turning off NETBIOS
altogether and running pure TCP/IP on your LAN (Local Area Network).
is this currently an issue still? Because I am working on a heartbeat-sensor and I was curious.
Your citation is not a normative reference, just another hobby site, and in this case it is dead wrong. None of this has anything to do with setSoTimeout(). He is totally confused between name resolution time, connect time, and read time. setSoTimeout() sets a read timeout, and is unaffected by the shenanigans he describes, whether accurately or otherwise, which wouldn't even happen at connect time as he states: they would happen at name-resolution time.
It's far from the only confusion to be found on that site, or even on that page, let me assure you. I told him about several errors on this page ten years ago, and about quite a lot of others, all of which remain uncorrected to this day, which gives you an idea of the site's accuracy, up-to-date-ness, and content review mechanisms. His only response was to add a rude remark about me. Unconvincing as a peer review mechanism.
Stick to authoritative sources.

How can I make a socket close immediately, bypassing the timeout period?

In Java, when you close a socket, it doesn't do anything anymore, but it actually closes the TCP connection after a timeout period.
I need to use thousands of sockets and I want them to be closed immediately after I close them, not after the timeout period, which wastes my time and my resources. What can I do?
I found out that by using socket.setReuseAddress(boolean), you can tell the JVM to reuse the port even if it's in the timeout period.
You are probably seeing sockets in TIME_WAIT state. This is the normal state for a socket to enter on the side of the connection that does the 'active close'. TIME_WAIT exists for a very good reason and so you should be careful of simply reusing addresses.
I wrote about TIME_WAIT, why it exists and what you can do about it when writing servers here on my blog: http://www.serverframework.com/asynchronousevents/2011/01/time-wait-and-its-design-implications-for-protocols-and-scalable-servers.html
In summary, if you can, change the protocol so that your clients enter TIME_WAIT.
If you're running a server, then ServerSocket is the proper solution. It will manage everything better than you doing it by hand through recycling and a host of other optimizations intended for running a server with Java.
Closing the socket disconnects the Java object from the operating system, which means that it isn't taking up any resources outside of the JVM, so it really shouldn't be a problem. But if the minimal overhead from Java's garbage collection/finalization scheme is too big of a burden, then Java isn't a valid solution (since your problem isn't specific to socket programming any more). Although I have to say that an efficient garbage collector is not much worse than explicitly managing memory (and can actually perform better).
'I want them to be closed exactly after closed them not after wasting my time and my resources!'
No you don't. You want TCP/IP to work correctly, and the TIME_WAIT state is a critically important part of that. If you're worried about the TIME_WAIT state, the quick answer is to be the one who receives the FIN rather than the one who first sends it.

How to detect dataloss with Java sockets?

I have the following situation: using a "classical" Java server (using ServerSocket) I would like to detect (as rapidly as possible) when the connection with the client failed unexpectedly (ie. non-gracefully / without a FIN packet).
The way I'm simulating this is as follows:
I'm running the server on a Linux box
I connect with telnet to the box
After the connection has succeeded I add "DROP" rule in the box's firewall
What happens is that the sending blocks after ~10k of data. I don't know for how long, but I've waited more than 10 minutes on several occasions. What I've researched so far:
Socket.setSoTimeout - however this affects only reads. If there are only writes, it doesn't have an effect
Checking for errors with PrintWriter.checkError(), since PW swallows the exceptions - however it never returns true
How could I detect this error condition, or at least configure the timeout value? (either at the JVM or at the OS level)
Update: after ~20min checkError returned true on the PrintWriter (using the server JVM 1.5 on a CentOS machine). Where is this timeout value configured?
The ~20 min timeout is because of standard TCP settings in Linux. It's really not a good idea to mess with them unless you know what you're doing. I had a similar project at work, where we were testing connection loss by disconnecting the network cable and things would just hang for a long time, exactly like you're seeing. We tried messing with the following TCP settings, which made the timeout quicker, but it caused side effects in other applications where connections would be broken when they shouldn't, due to small network delays when things got busy.
net.ipv4.tcp_retries2
net.ipv4.tcp_syn_retries
If you check the man page for tcp (man tcp) you can read about what these settings mean and maybe find other settings that might apply. You can either set them directly under /proc/sys/net/ipv4 or use sysctl.conf. These two were the ones we found made the send/recv fail quicker. Try setting them both to 1 and you'll see the send call fail a lot faster. Make sure to take not of the current settings before changing them.
I will reiterate that you really shouldn't mess with these settings. They can have side effects on the OS and other applications. The best solution is like Kitson says, use a heartbeat and/or application level timeout.
Also look into how to create a non-blocking socket, so that the send call won't block like that. Although keep in mind that sending with a non-blocking socket is usually successful as long as there's room in the send buffer. That's why it takes around 10k of data before it blocks, even though you broke the connection before that.
The only sure fire way is to generate application level "checks" instead of relying on the transport level. For example, a bi-directional heartbeat message, where if either end does not get the expected message, it closes and resets the connection.

Categories

Resources