i have a java program connect to server through xot protocol.
My lib i use can handle connect timeout, but there is no method like setSoTimeout() to handle timeout when send & recv data.
so, anyone could suggest me some solution for this problem.
thanks
Quan
One option is to spawn a thread to do the writing and join(timeout) it. Likewise with reading from the connection. Obviously kill the thread (and treat the connection as in an indeterminate state) when the timeout expires (as opposed to the thread dieing).
'Socket.setSoTimeout()' should apply to recv as well. See its javadoc.
public void setSoTimeout(int timeout) throws SocketException
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.
Related
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.
I am quite confused about socket.setSoTimeout( int ) method.
In scenario when i call
socket.setSoTimeout(4000);
try{
string data = input.read();
}catch (InterruptedIOException e) {
}
when calling setSoTimeout() , does it pauses the sokcet and resumes after 4000 milliseconds? Or it will just completely block all reading from socket and if anything attempts to read from it while setSoTimeout is still active it will throw exception?
If the latest , why is this usefull at all? By documentation after timeout expired the exception is thrown automaticlly.
Thanks for clarification.
The key part of the documentation for Socket.setSoTimeout() is:
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.
This is saying that a read on the socket will be prevented from blocking any longer than the specified time (which is perhaps more clear when interpreted in light of the meaning of "timeout", and is certainly more clear if you are familiar with the system-level socket interface). It does not say that a read is guaranteed to block for that long, which indeed would be of questionable utility.
Among the problems solved by setting a timeout is that of handling clients that are uncleanly disconnected without closing the connection. The local machine has no way to detect that that has happened, so without a timeout, an attempt to read from a socket connected to such a client will block indefinitely.
I think,setSotimeout denotes the amount of time a server can wait for a response to read.if timeout value exceeds ,exception will be thrown.
for example.If you set setSotimeout(4000) to socket,
Socket will wait for only 4 secs for the receiver to respond,it throws exception after 4 secs.
It will be useful in slow connection networks or bad servers.
It avoids waiting for response.
I have a java socket calling a server. However, I do not know at which address I can reach the server, so I put several sockets in several threads and they try to reach the server each on one address. My probem is that I do not want to wait for the timeout but have no idea how to stop the sockets and their threads properly.
Code:
socket = new Socket();
socket.connect(endpoint, timeout); // **Blocking method**
OutputStream out = socket.getOutputStream();
//Write Data here
How can I interrupt the operation? I consider Thread.stop() a bad style and it also does not work properly. .NET Tcp Endpoints have a non-blocking pending method that allows uinsg boolean flags but I could not find something similiar
I do not know at which address I can reach the server, so I put
several sockets in several threads and they try to reach the server
each on one address.
BAD. BAD Decision. Perform some logical step to determine the server's address. Or, perform something that helps you know about the server's IP-Address.
Do this way, only if it is the last hope.
My problem is that I do not want to wait for the
timeout but have no idea how to stop the sockets and their threads
properly.
You don't have any other option that timeout. Socket.connect() is blocking. You can't do anything than waiting.
You've to wait for timeout because that is the logical way to close the socket object created. You can't just do close directly, until a timeout. Reduce the timeout to the limit when your result should come(connection should be accepted).
How can I interrupt the operation? I consider Thread.stop() a bad
style and it also does not work properly.
Yes, you should not perform Thread.stop() or Thread.interrupt(). These are bad programming styles.
If the timeout expires, make the close() operation on socket.
You should set a socket timeout for the client-socket. It is the best-practice to set a timeout for sockets. The timeout should be around 10 seconds to more depending on the needs.
You can set the timeout in your current code by calling
socket.setSoTimeout(timeout); for reading timeout, OR
for connect timeout, connect(endpoint,timeout) as you've done in your code.
If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
You're probably not using a try-catch-finally in your code. That'd be a better design here.
As you're doing a connect timeout, so your code can be amended to exit the blocking method like as shown below :
try{
socket = new Socket();
socket.connect(endpoint,timeout); // **Blocking method**
OutputStream out = socket.getOutputStream();
//Write Data here
}
catch(Exception e){
e.printStackTrace();
}
finally{
socket.close();
}
I am making an application where the client sends a message to the server and then waits for 5 seconds (lets assume) for the server to respond and if there is no return message, it retries again. If the server responds with the message then the client process it. This goes on in loop and again happens after sometime.
For this purpose I was thinking to use setSoTimeout(time) on the Client Socket but after reading the javadoc and a lot of explanations on the internet I am confused as to whether this approach is right.
What I read on the internet
(1) If I use setSoTimeout on the socket then it gives the timeout for the duration in which the connection needs to be established and if it is not established then it retries to establish the connection for the given time.
(2) If I use setSoTimeout on the socket then it waits for incoming messages for the specified time interval and if no message is received then it stops waiting.
My questions are -
(1) Which of the above are true ?
(2) If the second statement is true, then can I use it for my implementation ?
(3) If the second statement is true, when does the timeout timer kickoff exactly ? Is it when I declare the socket and set the timeout period on it or is it when I send the message ?
If either of the explanation don't apply to my case then what is it that I should do to wait for a fixed interval of time on the client side for the server to reply ? If the reply does come I should process it and move on and redo the same process. If the reply doesn't come I should move ahead and redo the whole process again.
(1) If I use setSoTimeout() on the socket then it gives the timeout for the duration in which the connection needs to be established and if it is not established then it retries to establish the connection for the given time.
This is incorrect. setSoTimeout() does not cause re-establishment of the connection at all, let alone 'for the given time'.
(2) If I use setSoTimeout() on the socket then it waits for incoming messages for the specified time interval and if no message is received then it stops waiting.
This is slightly more accurate, but there is no such thing as a message in TCP.
The correct explanation is that it blocks for up to the specified timeout for at least one byte to arrive. If nothing arrives within the timeout, a SocketTimeoutException is thrown.
(1) Which of the above are true?
Neither.
(2) If the second statement is true, then can I use it for my implementation?
It isn't, so the second part doesn't apply, but if any statement is true you can use it as part of your implementation. You don't have to ask.
(3) If the second statement is true, when does the timeout timer kickoff exactly?
When you call read().
Is it when I declare the socket and set the timeout period on it or is it when I send the message?
Neither.
If either of the explanation don't apply to my case then what is it that I should do to wait for a fixed interval of time on the client side for the server to reply?
Set a read timeout.
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.)