Reputation: 971
When I create a socket:
Socket socket = new Socket(ipAddress, port);
It throws an exception, which is OK, because the IP address is not available. (The test variables where String ipAddress = "192.168.0.3"
and int port = 300
.)
The problem is: how do I set it to timeout for that socket?
When I create the socket, how do I reduce the time before I get a UnknownHostException
and get the socket to timeout?
Upvotes: 97
Views: 220818
Reputation: 10670
One solution is to execute the DNS resolution on a different thread which is given only a certain amount of time to complete.
Here's a simple utility that can help you do this:
public class TimeSliceExecutor {
public static class TimeSliceExecutorException extends RuntimeException {
public TimeSliceExecutorException(String message, Throwable cause) {
super(message, cause);
}
}
public static void execute(Runnable runnable, long timeoutInMillis) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
Future<?> future = executor.submit(runnable);
getFuture(future, timeoutInMillis);
}
finally {
if (executor != null) {
executor.shutdown();
}
}
}
public static <T> T execute(Callable<T> callable, long timeoutInMillis) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
Future<T> future = executor.submit(callable);
return getFuture(future, timeoutInMillis);
}
finally {
if (executor != null) {
executor.shutdown();
}
}
}
public static <T> T getFuture(Future<T> future, long timeoutInMillis) {
try {
return future.get(timeoutInMillis, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new TimeSliceExecutorException("Interrupton exception", ex);
}
catch (ExecutionException ex) {
throw new TimeSliceExecutorException("Execution exception", ex);
}
catch (TimeoutException ex) {
throw new TimeSliceExecutorException(String.format("%dms timeout reached", timeoutInMillis), ex);
}
}
}
Then build the socket along these lines:
private Socket buildSocket() throws IOException {
final Socket socket = new Socket();
socket.setSoTimeout(socketTimeout);
socket.connect(new InetSocketAddress(resolveHost(host, dnsTimeout), port), connectionTimeout);
return socket;
}
private static InetAddress resolveHost(String host, long dnsTimeout) throws IOException {
try {
return TimeSliceExecutor.execute(() -> InetAddress.getByName(host), dnsTimeout);
}
catch (TimeSliceExecutor.TimeSliceExecutorException ex) {
throw new UnknownHostException(host);
}
}
Ref: https://stackoverflow.com/a/70610305/225217
Upvotes: 1
Reputation: 14187
You don't set a timeout for the socket, you set a timeout for the operations you perform on that socket.
For example socket.connect(otherAddress, timeout)
Or socket.setSoTimeout(timeout)
for setting a timeout on read()
operations.
See: http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html
Upvotes: 48
Reputation: 311039
You can't control the timeout due to UnknownHostException
. These are DNS timings. You can only control the connect timeout given a valid host. None of the preceding answers addresses this point correctly.
But I find it hard to believe that you are really getting an UnknownHostException
when you specify an IP address rather than a hostname.
EDIT To control Java's DNS timeouts see this answer.
Upvotes: 9
Reputation: 1833
You could use the following solution:
SocketAddress sockaddr = new InetSocketAddress(ip, port);
// Create your socket
Socket socket = new Socket();
// Connect with 10 s timeout
socket.connect(sockaddr, 10000);
Hope it helps!
Upvotes: 21
Reputation: 421220
Use the Socket()
constructor, and connect(SocketAddress endpoint, int timeout)
method instead.
In your case it would look something like:
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, port), 1000);
Quoting from the documentation
connect
public void connect(SocketAddress endpoint, int timeout) throws IOException
Connects this socket to the server with a specified timeout value. A timeout of zero is interpreted as an infinite timeout. The connection will then block until established or an error occurs.
Parameters:
endpoint
- the SocketAddress
timeout
- the timeout value to be used in milliseconds.Throws:
IOException
- if an error occurs during the connection
SocketTimeoutException
- if timeout expires before connecting
IllegalBlockingModeException
- if this socket has an associated channel, and the channel is in non-blocking mode
IllegalArgumentException
- if endpoint is null or is a SocketAddress subclass not supported by this socketSince: 1.4
Upvotes: 181
Reputation: 75659
Use the default constructor for Socket and then use the connect() method.
Upvotes: 8