I have a java application which manages several socket connections to devices. I have no control over the protocol which these devices implement, and now I want my java application to send heartbeats for each device. The devices do not send data, but only respond to commands.
The javadoc for InputStream.read() states that if the end of stream is reached, it will return -1. So that seems like a reasonable way to check if the connection is open. But when I implement this solution, there are no bytes available (since the device only responds to commands), and since the connection is open, it will hang at the read call forever. Example, I peek at one byte and if that would be -1 the heartbeat would be "unhealthy":
public static void main(final String[] args) throws IOException {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress("192.168.30.99", 25901), 1000);
System.out.println("Connected");
final BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
bis.mark(1);
System.out.println(bis.read()); // Stalls forever here
bis.reset();
System.out.println("Done");
}
}
Is it reasonable to say that, if no byte is received within x milliseconds, the device is connected?
Is there any surefire way to check socket connectivity without heartbeats where the ip and port is important?
Is there any surefire way to check socket connectivity without
heartbeats where the ip and port is important?
No, you can't reliably know if the other end is alive unless you try to communicate with it.
If the other end doesn't have a no-op ping function, you're pretty much out of luck. Waiting in a blocking read() call won't help you if the connection gets cut off.
Is it reasonable to say that, if no byte is received within x
milliseconds, the device is connected?
No. It means that the device hasn't sent anything in x milliseconds. Which is normal, as it only responds to commands.
when the other end of socket do not write any byte and wait to read from socket first, blocking on read is the default behavior.
with no control over the protocol , little can be done.
it is reasonable to say, successful connect is a weaker heartbeat.
you don't have to wait for x miliseconds which makes no difference on such protocol
another tricky way , you can try to send a few bytes that most unlikely being a valid command,
for example the '\0' or '\n' ,
hoping that it will do no harm to the device and the device can close socket actively on such invalid command.
when the other end closes socket actively , read call on such socket should return -1
the better heartbeat way always have something to do with the protocol,
as the no-op ping command suggested by #Kayaman
Maybe TCP level keep-alive is solution for you:
You can turn it on by using command:
socket.setKeepAlive(true);
It sets SO_KEEPALIVE socket option. Quote from SocketOptions java-API:
When the keepalive option is set for a TCP socket and no data has been
exchanged across the socket in either direction for 2 hours (NOTE: the
actual value is implementation dependent), TCP automatically sends a
keepalive probe to the peer. This probe is a TCP segment to which the
peer must respond. One of three responses is expected: 1. The peer
responds with the expected ACK. The application is not notified (since
everything is OK). TCP will send another probe following another 2
hours of inactivity. 2. The peer responds with an RST, which tells the
local TCP that the peer host has crashed and rebooted. The socket is
closed. 3. There is no response from the peer. The socket is closed.
The purpose of this option is to detect if the peer host crashes.
Valid only for TCP socket: SocketImpl
You could also use SO_TIMEOUT by using:
socket.setSoTimeout(timeout);
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.
Call those right after connect() or accept() calls, before the program enters to
'no control of underlying protocl' -state.
Related
I have Java code that sets up a server on a particular port, some code is run in python that uses this server, and then the port is closed. I've set it up so that after each python run, the java loops and repeats this process (setting up a new server, serving, then closing).
I notice that when the python call is short (about <10s), that the next time Java tries to set up this port, it will fail. Are there rules about how long you must wait between successively setting up the same port on Java?
Ports can be finicky with this type of thing. They're not meant to be opened and closed all the time. You should leave the socket open and just handle each connection within, like this:
ServerSocket listener = new ServerSocket(9090);
try {
while (true) {
Socket socket = listener.accept();
try {
PrintWriter out =
new PrintWriter(socket.getOutputStream(), true);
out.println(new Date().toString());
} finally {
socket.close();
}
}
}
finally {
listener.close();
}
(credit: http://cs.lmu.edu/~ray/notes/javanetexamples/)
In general, it is better to maintain a long-running ServerSocket that serves multiple requests, as others have already answered and commented. However, I have found that sometimes there is a legitimate need to stop and start a server in rapid succession. One example is an integration test suite that involves stopping and restarting the server in different configurations to repeat test runs.
If you really have this need, then you might be interested in ServerSocket#setReuseAddress(boolean).
Enable/disable the SO_REUSEADDR socket option.
When a TCP connection is closed the connection may remain in a timeout state for a period of time after the connection is closed (typically known as the TIME_WAIT state or 2MSL wait state). For applications using a well known socket address or port it may not be possible to bind a socket to the required SocketAddress if there is a connection in the timeout state involving the socket address or port.
Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even though a previous connection is in a timeout state.
This ultimately enables the SO_REUSEADDR socket option. One source of information for more details on these socket options is the Linux socket man page.
However, please be aware that the exact perceived behavior can very greatly across different platforms. In particular, beware of the extremely different and dangerous behavior of this setting on Windows, as documented in the MSDN article Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE. Basically, SO_REUSEADDR on Windows can allow any arbitrary process to "steal" a socket already in use by another process, resulting in indeterminate behavior.
The SO_REUSEADDR socket option allows a socket to forcibly bind to a port in use by another socket. The second socket calls setsockopt with the optname parameter set to SO_REUSEADDR and the optval parameter set to a boolean value of TRUE before calling bind on the same port as the original socket. Once the second socket has successfully bound, the behavior for all sockets bound to that port is indeterminate. For example, if all of the sockets on the same port provide TCP service, any incoming TCP connection requests over the port cannot be guaranteed to be handled by the correct socket — the behavior is non-deterministic. A malicious program can use SO_REUSEADDR to forcibly bind sockets already in use for standard network protocol services in order to deny access to those service. No special privileges are required to use this option.
I advise people to think carefully and make sure you're confident with this setting rather than blindly turning it on. There is also a phenomenal prior question and answer about the relevant socket options:
Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?
I am writing a program that has a Java Server/Client socket. There will be many messages sent back and forth, and in some situations, sending a message to the server and waiting for a period of time until the server has sent back a "execute" message.
Here is what I have planned:
1 Server (machine could possibly have antivirus security on it)
3 Clients (with room for more clients in future)
Parallel and Interleaved synchronization being carried out on the server side based up the clients output to the server.
When all machines are ready (in sync), when parallel all clients will be sent an "execute" message, when interleave clients will be sent an "execute" command in sequential order 1 by 1
I have started to build the program to have this setup above, and once a message is received on the server, the servers performs actions based upon the input and then sends back a message to the client. I have had problems in the past where messages were not sent or received properly, so my question is:
Do I keep the socket alive until then end of my program?
Or do I keep the socket open only until a successful transmission (a full handshake) has taken place and then close the socket? Leaving the client to connect again next time it wants to send a message.
You should certainly keep TCP connections open for as long as possible, but be prepared to create a new one on failure. You will need to use read timeouts at both ends to detect those.
Q: Should I open a new socket each connection, or keep it around and re-use it for subsequent connections?
A: "It depends".
I would encourage you to "Keep it Simple" and simply open new socket as needed ... until you find that you need otherwise.
By all means: keep the socket open for as long as you reasonably expect a "dialog" between your client and server. Don't force the client to establish a new connection if he's likely to want to talk again reasonably quickly.
Finally, take a look at these links regarding "Connection Pooling":
http://www.javacodegeeks.com/2013/08/simple-and-lightweight-pool-implementation.html
http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
Whether or not you close the socket after a message depends on the protocol that you use between the server and the clients. Probably you define this yourself.
What is probably more important, is that you are able to serve multiple clients in parallel. Therefore, you need to start a separate thread for every client that requests a connection.
Personally, I made some applications with socket communication. To prevent keeping resources for too long when they are not used, but also not closing and reopening constantly when a connection is heavily used, I added a connection supervisor. This is yet another thread, that does is started when a connection is opened, and just performs a countdown from a predefined value (e.g. countdown from 60, decreqsing the value every second for a supervision time of 1 minute). When the counter reaches zero, order to close the socket, and terminate that particular thread.
When a socket is open, and receives a new message, then reset the supervision counter, so the socket will remain open, as long as the time between messages is less than 1 minute.
Using the App Engine Trusted Tester Sockets to connect to APNS. Writing to socket works fine.
But the problem is that the Socket gets reclaimed after 2 minutes of inactivity. It says in the Trusted Tester Website that any socket operation keeps the socket alive for further 2 minutes. It is nicer to keep the socket open until APNS decides to close the connection.
After trying pretty much all of the Socket API methods short of writing to the Output Stream, Socket gets closed after 2 minutes no matter what. What have I missed?
Deployed on java backend.
You can't keep a socket connected to APNS artifically open; without sending actual push notifications. The only way to keep it open is to send some arbitrary data/bytes but that would result in an immediate closure of the socket; APNS closes the connection as soon as it detects something that does not conform to the protocol, i.e. something that is not an actual push notification.
SO_KEEPALIVE
What about SO_KEEPALIVE? App Engine explicitly says it is supported. I think it just means it won't throw an exception when you call Socket.setKeepAlive(true); calls wanted to set socket options raised Not Implemented exceptions before. Even if you enable keep-alive your socket will be reclaimed (closed) if you don't send something for more than 2 minutes; at least on App Engine as of now.
Actually, it's not a big surprise. RFC1122 that specifies TCP Keep Alive explicitly states that TCP Keep Alives are not to be sent more than once every two hours, and then, it is only necessary if there was no other traffic. Although, it also says that this interval must be also configurable, there is no API on java.net.Socket you could use to configure that (most probably because it's highly OS dependent) and I doubt it would be set to 2 minutes on App Engine.
SO_TIMEOUT
What about SO_TIMEOUT? It is for something completely else. The javadoc of Socket.setSoTimeout() states:
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.
That is, when read() is blocking for too long because there's nothing to read you can say "ok, I don't want to wait (block) anymore; let's do something else instead". It's not going to help with our "2 minutes" problem.
What then?
The only way you can work around this problem is this: detect when a connection is reclaimed/closed then throw it away and open a new connection. And there is a library which supports exactly that.
Check out java-apns-gae.
It's an open-source Java APNS library that was specifically designed to work (and be used) on Google App Engine.
https://github.com/ZsoltSafrany/java-apns-gae
Did you try getSoLinger()? That may be the getSocketOpt that works (kind of) currently and it may reset the 2 minute timeout. In theory, also doing a zero byte read would as well but I'm not sure that would, if you try that, use this method on the inputstream.
public int read(byte b[], int off, int len)
If these suggestions don't work, please file an issue with the App Engine issue tracker.
There will be some other fixes coming, e.g. using socket options etc.
Use getpeername().
From https://developers.google.com/appengine/docs/java/sockets/overview ...
Sockets may be reclaimed after 2 minutes of inactivity; any socket
operation (e.g. getpeername) keeps the socket alive for a further 2
minutes. (Notice that you cannot Select between multiple available
sockets because that requires java.nio.SocketChannel which is not
currently supported.)
How do I create a TCP socket in Java?
How do I create such a TCP connection that it terminates only when I tell it to otherwise it remains open?
How do I use keepalives to know whether the server or client is still available?
Please Help!
How do I create a TCP socket in Java?
Socket socket = new Socket(hostname, port);
http://docs.oracle.com/javase/tutorial/networking/sockets/index.html
How do I create such a TCP connection that it terminates only when I tell it to otherwise it remains open?
They will remain open until either you or the other end closes it.
How do I use keepalives to know whether the server or client is still available?
That is up to you. You can send different messages, one of which is a heartbeat which tells the other end you are alive.
A common thing to do if you are sending binary messages is to send the length as an unsigned short or int value. I use a message of "length" 0 as a heartbeat.
The class java.net.Socket is what you are searching for.
I want to check when the internet goes off can i capture that event .I am not getting the proper API or any example which would explain the same .
I am using socket for (TCP)communication and I open a socket when the network is available. I have observed that the socket does not give any exception in case the network goes off.
If any one had done or any example links would be really helpful Thanks in advance
The problem is that no event 'network down' exists in tcp connections, they just go down.
As suggested by Jerome you should check if timeout is reached.
Of course if network goes down you won't receive packets neither be able to send them so the underlying InputStream and OutputStream will throw an IOException but just when they'll realize that network is not working properly (usually 2*rtt = 120 seconds, it depends how TCP layer is managed).
Look state diagram by yourself:
What typically happens is that when in ESTABLISHED your socket will send data over the socket while waiting for ACK from destination. ACK won't come since network went off so your socket's window fills up and socket starts resending packets until real timeout intervenes throwing the exception.
Another case is when network goes off and your socket realizes that it cannot write anymore on channel: it will throw an exception imediately upon calling outStream.write(...).
It's not that easy to tell whether the network is off or just slow.
If you set Timeouts, it will throw exception if it takes too long:
For sockets:
socket.setSoTimeout(CONNECTION_TIMEOUT);
For HttpURLConnections:
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setConnectTimeout(CONNECTION_TIMEOUT);
con.setReadTimeout(CONNECTION_TIMEOUT);
TCP is designed to be quiet when idle. There is no administrative packets on wire when there is no pending packet. If the connection is dead while idle, you will not know, no matter what the setting of the timeout is. It does have keepalives but it's pretty much useless at the recommended frequency of 2 hours and longer.
You need to build some heartbeat or keepalive in your application protocol to detect stale connections. Keepalive is nothing but a noop packet sent at regular interval to trigger TCP timeout when connection is down. In my app, I do this every 10 seconds.
Why don't you try pinging www.google.com
See http://java.sun.com/j2se/1.5.0/docs/guide/nio/example/Ping.java