Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why is connect() taking one second to return when trying to connect to a closed port ?

47 views
Skip to first unread message

Xavier Roche

unread,
Mar 11, 2011, 10:29:14 AM3/11/11
to
Hi folks,

When attempting to connect to a closed port, most operating systems
return immediately from connect(), with a ECONNREFUSED. Attempting to do
a non-blocking connect() (with a select() to watch for an error) will
also trigger an error nearly immediately, as soon as the remote host
refusal will be seen.

On Windows, the "connection refused" appears to be seen only one second
after the connection was actually refused, as if Windows was retrying to
connect during 1000ms, and would eventually give up ; even when trying
to connect to a closed port on localhost.

(This behavior is easily reproducible with java ; with a non-blocking
connect(), for example)

Is this behavior "normal" ? Is there a way to disable it ?

Thanks for any enlightenment from winsock experts :)

Xavier Roche

unread,
Mar 11, 2011, 12:57:11 PM3/11/11
to
Le 11/03/2011 16:29, Xavier Roche a écrit :
> On Windows, the "connection refused" appears to be seen only one second
> after the connection was actually refused, as if Windows was retrying to
> connect during 1000ms, and would eventually give up ; even when trying
> to connect to a closed port on localhost.

Hmm, it appears that this.. "unusual" behavior is a design choice (see
below). Unfortunately, there does not seem to be any way to
programatically change this :(

<http://support.microsoft.com/kb/175523/en-us>
"Upon receiving the ACK/RST client from the target host, the client
determines that there is indeed no service listening there. In the
Microsoft Winsock implementation of TCP, a pending connection will keep
attempting to issue SYN packets until a maximum retry value is reached
(set in the registry, this value defaults to 3 extra times). Since an
ACK/RST was received from the target host, the TCP layer knows that the
target host is indeed reachable and will not double the time-out value
in the packet's IP header, as is standard during connection attempts
with unacknowledged SYNs. Instead, the pending connection will wait for
the base connection's time-out value and reissue another SYN packet to
initiate a connection. As long as an ACK/RST packet from an unused port
is received, the time-out value will not increase and the process will
repeat until the maximum retry value is reached.

This behavior may result in poor performance if for some reason a
process repeatedly issues connect() calls to ports with nothing
listening there, resulting in the error WSAECONNREFUSED. Note that with
other implementations of TCP, such as those commonly found in many UNIX
systems, the connect() fails immediately upon the receipt of the first
ACK/RST packet, resulting in the awareness of an error very quickly.
However, this behavior is not specified in the RFCs and is left to each
implementation to decide. The approach of Microsoft platforms is that
the system administrator has the freedom to adjust TCP
performance-related settings to their own tastes, namely the maximum
retry that defaults to 3. The advantage of this is that the service
you're trying to reach may have temporarily shut down and might
resurface in between SYN attempts. In this case, it's convenient that
the connect() waited long enough to obtain a connection since the
service really was there."

Michael Wojcik

unread,
Mar 14, 2011, 9:29:18 AM3/14/11
to
Xavier Roche wrote:
> Le 11/03/2011 16:29, Xavier Roche a écrit :
>> On Windows, the "connection refused" appears to be seen only one second
>> after the connection was actually refused, as if Windows was retrying to
>> connect during 1000ms, and would eventually give up ; even when trying
>> to connect to a closed port on localhost.
>
> Hmm, it appears that this.. "unusual" behavior is a design choice (see
> below). Unfortunately, there does not seem to be any way to
> programatically change this :(

Yes. I believe this misfeature was introduced to compensate for
another misfeature in the Winsock stack.

Winsock, unlike most TCP implementations, will send an RST in response
to a client's SYN if the server's listen queue is full. Most
implementations simply discard the SYN; this is sensible, since the
client's TCP ACK timer will expire and it will re-send the SYN, by
which time the server may have caught up and drained the listen queue,
if the problem is simply a burst of connection attempts.

By sending a RST, Winsock makes it impossible for the client to
distinguish between a transient listen-queue-full condition and a
persistent no-listening-process condition.

This is aggravated by Microsoft's policy of crippling non-Server
versions of Windows; one of the limits they impose is on the listen
queue size, which is clamped to some low value.

So Winsock tries to compensate by blindly retrying in connect() for a
while in the face of RSTs from the server. Some apps go further and
retry failed connect()s, until they reach some internal limit or the
user gets sick of it and cancels the operation.

--
Michael Wojcik
Micro Focus
Rhetoric & Writing, Michigan State University

Xavier Roche

unread,
Mar 14, 2011, 11:51:36 AM3/14/11
to
On 03/14/2011 02:29 PM, Michael Wojcik wrote:
> By sending a RST, Winsock makes it impossible for the client to
> distinguish between a transient listen-queue-full condition and a
> persistent no-listening-process condition.

Darn, this "makes sense" why the retransmission is executed in case of
closed port.

I'm wondering if the RST in case of queue full is a bug, or a choice,
due to imprecise specifications (http://www.faqs.org/rfcs/rfc793.html)
(A quick look at the RFC does not seem to give any clear answer)

> So Winsock tries to compensate by blindly retrying in connect() for a
> while in the face of RSTs from the server. Some apps go further and
> retry failed connect()s, until they reach some internal limit or the
> user gets sick of it and cancels the operation.

Sheesh. And polling (select()) the socket for less than 1000ms will
always result in a "time out" error ; as RST are not seen as errors
until the retransmission count is not reached.

I guess I am doomed :)

Thanks for the explanation anyway.

[Hmm, would playing with raw sockets and out-of-band data be a solution
? I won't definitely try this insane solution that anyway, but in case ..]

Michael Wojcik

unread,
Mar 18, 2011, 8:35:31 AM3/18/11
to
Xavier Roche wrote:
> On 03/14/2011 02:29 PM, Michael Wojcik wrote:
>> By sending a RST, Winsock makes it impossible for the client to
>> distinguish between a transient listen-queue-full condition and a
>> persistent no-listening-process condition.
>
> I'm wondering if the RST in case of queue full is a bug, or a choice,
> due to imprecise specifications (http://www.faqs.org/rfcs/rfc793.html)

I think it's allowed by the standards - if memory serves, this was
discussed some years back on comp.protocol.tcp-ip. It's just a poor
choice, aggravated by Microsoft's deliberate crippling of non-Server
versions of the NT-based Windows products (for price-point
differentiation).

0 new messages