SYNOPSIS
--------
Long Socket.connect() timeouts not honored
OPERATING SYSTEM(S)
-------------------
Windows (tested on Windows XP)
Linux (tested on Ubuntu)
FULL JDK VERSION(S)
-------------------
All (1.4.2, 5.0, 6 and 7)
PROBLEM DESCRIPTION
-------------------
Timeout values passed into Socket.connect() are not always honoured. Specifically, values larger than 21 seconds are not honoured on Windows and Linux - the connection attempt just times out after 21 seconds.
It's quite possible that the OS is abandoning the connection attempt. On Windows, the registry setting TcpMaxConnectRetransmissions seems to govern the behaviour of the OS:
--------
TcpMaxConnectRetransmissions
Key: Tcpip\Parameters
Value Type: REG_DWORD - Number
Valid Range: 0 - 0xFFFFFFFF
Default: 2
Description: This parameter determines the number of times that TCP retransmits a connect request (SYN) before aborting the attempt. The retransmission timeout is doubled with each successive retransmission in a particular connect attempt. The initial timeout value is three seconds.
--------
http://support.microsoft.com/kb/314053
The two retries would result in an overall timeout of 21 seconds (3 + 6 +12 = 21).
On Linux, the equivalent OS setting appears to be tcp_synack_retries or
tcp_syn_retries, but these default to 5, which should give an OS timeout of 3 minutes. However, on Linux I see the same limited timeout as Windows - 21 seconds.
So this behaviour may be caused by the OS, but shouldn't Java respect the timeout passed into the Socket.connect() method regardless? There doesn't seem to be any reason why the connect() method couldn't continue to retry after the first OS connection attempt times out.
REPRODUCTION INSTRUCTIONS
-------------------------
1. javac Timeout.java
2. java Timeout 30000
Expected output:
Timed out after 30.000 seconds (value may deviate from 30s slightly)
Observed output:
Timed out after 21.672 seconds (value is approximately 21 seconds)
TESTCASE
--------
import java.net.*;
class Timeout {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java Timeout [timeout (ms)]");
System.exit(1);
}
int timeout = Integer.parseInt(args[0]);
long startTime = 0;
long endTime = 0;
Socket s = new Socket();
// Create a non-existent endpoint to guarantee a connection timeout
InetSocketAddress endpoint = new InetSocketAddress(InetAddress.getByName("10.0.0.1"), 55555);
try {
startTime = System.currentTimeMillis();
s.connect(endpoint, timeout);
} catch (Exception e) {
endTime = System.currentTimeMillis();
System.out.println("Timed out after " + ((float)(endTime - startTime))/1000 + " seconds");
}
}
}
WORKAROUND
----------
On Windows, set the registry key TcpMaxConnectRetransmissions to a value high enough to allow the specified timeout.
--------
Long Socket.connect() timeouts not honored
OPERATING SYSTEM(S)
-------------------
Windows (tested on Windows XP)
Linux (tested on Ubuntu)
FULL JDK VERSION(S)
-------------------
All (1.4.2, 5.0, 6 and 7)
PROBLEM DESCRIPTION
-------------------
Timeout values passed into Socket.connect() are not always honoured. Specifically, values larger than 21 seconds are not honoured on Windows and Linux - the connection attempt just times out after 21 seconds.
It's quite possible that the OS is abandoning the connection attempt. On Windows, the registry setting TcpMaxConnectRetransmissions seems to govern the behaviour of the OS:
--------
TcpMaxConnectRetransmissions
Key: Tcpip\Parameters
Value Type: REG_DWORD - Number
Valid Range: 0 - 0xFFFFFFFF
Default: 2
Description: This parameter determines the number of times that TCP retransmits a connect request (SYN) before aborting the attempt. The retransmission timeout is doubled with each successive retransmission in a particular connect attempt. The initial timeout value is three seconds.
--------
http://support.microsoft.com/kb/314053
The two retries would result in an overall timeout of 21 seconds (3 + 6 +12 = 21).
On Linux, the equivalent OS setting appears to be tcp_synack_retries or
tcp_syn_retries, but these default to 5, which should give an OS timeout of 3 minutes. However, on Linux I see the same limited timeout as Windows - 21 seconds.
So this behaviour may be caused by the OS, but shouldn't Java respect the timeout passed into the Socket.connect() method regardless? There doesn't seem to be any reason why the connect() method couldn't continue to retry after the first OS connection attempt times out.
REPRODUCTION INSTRUCTIONS
-------------------------
1. javac Timeout.java
2. java Timeout 30000
Expected output:
Timed out after 30.000 seconds (value may deviate from 30s slightly)
Observed output:
Timed out after 21.672 seconds (value is approximately 21 seconds)
TESTCASE
--------
import java.net.*;
class Timeout {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java Timeout [timeout (ms)]");
System.exit(1);
}
int timeout = Integer.parseInt(args[0]);
long startTime = 0;
long endTime = 0;
Socket s = new Socket();
// Create a non-existent endpoint to guarantee a connection timeout
InetSocketAddress endpoint = new InetSocketAddress(InetAddress.getByName("10.0.0.1"), 55555);
try {
startTime = System.currentTimeMillis();
s.connect(endpoint, timeout);
} catch (Exception e) {
endTime = System.currentTimeMillis();
System.out.println("Timed out after " + ((float)(endTime - startTime))/1000 + " seconds");
}
}
}
WORKAROUND
----------
On Windows, set the registry key TcpMaxConnectRetransmissions to a value high enough to allow the specified timeout.
- csr for
-
JDK-8359249 (spec) Socket.connect(addr,timeout) not clear if IOException because of TCP timeout
-
- Draft
-
- links to
-
Review(master) openjdk/jdk/25690