14

I was given 10 new PCs, all (supposedly) with Windows 7 Pro freshly installed and nothing else done to them.

I have a program, coded in Delphi XE2, using Indy 10 components for the networking. I set the "connect timeout" and "read timeout" properties of my TIdTcpCleint to 500ms, set "resuse socket" to 'o/s dependant'" (I also tried a build with it set to No) and leave "use Nagle" (whatever that is set to True (I also tried with false).

Here's the problem: when I run the same .EXE on these PCs and test the case where I pull the network cable, my debug trace shows the connect attempt / connect timeout happening in the same second or the next second (with a granularity of 1 second) - but on others it is 20 or 21 seconds before I see the conenction timeout.

It would seem some of that the PCs are not totally "fresh install" as claimed, although I see no aps installed. Maybe some one installed somethign then removed it, maybe they tried to tweak performance.

Before I reinstall Windows on 10 PCs, can anyone suggest where to look? Does 20 (or 21) seconds ring a bell with regard to TCP Client connect timeout?

[update] I am attempting to connect directly to a specific IP Address, so I am not sure if @Nikolai suggestion to check DNS is relevant. Sorry for not mentioning this originally.

[upperdate] the program does not attempt to keep the socket open. It connects, sends some data & disconnects - repeatedly, for each new piece of data.

13
  • 2
    Random guess - check how DNS works on those different sets of PCs. Commented Aug 22, 2012 at 2:47
  • 3
    Run wireshark on the box and see what is happening Commented Aug 22, 2012 at 2:54
  • 2
    Save ya a little time - wireshark.org Commented Aug 22, 2012 at 3:09
  • 2
    Why do you pull the network cable? You could as well try to connect to an invalid IP address, the result should be the same! Pulling a cable does not automatically trigger a "reconnect", only the app code can do this.
    – mjn
    Commented Aug 22, 2012 at 4:41
  • 2
    @Mawg IIRC "ReadTimeout" means how many ms between each byte read is the maximum time allowed, 500 is quite a lot, I'd go for something lower.
    – user497849
    Commented Aug 22, 2012 at 8:58

2 Answers 2

8
+100

Sadly, this is working as intended. The connect did already timeout. Indy made the determination that the connect would fail in the 500 milliseconds that you asked it to. However, that does not guarantee the function will return.

After the connect times out, Indy spins down the connection to release all of its resources. It does this synchronously. This means that you wind up waiting for the underlying TCP operation to fail. This typically takes 20 seconds.

The solution is to call connect in a thread. Believe it or not, this is what Indy already does to implement the timeout. However, when it times out waiting for the thread, it tries to shut down the connection in the main thread. You need to defer that to a worker thread.

As for why it happens immediately on some systems and in 20 seconds on others, it depends on the precise networking configuration. For example, if IPv6 is enabled, the stack may attempt to use an IPv6-to-IPv4 connection, and that may not report down even if the physical interface is down. Immediate detection of connection impossibility is never guaranteed and you shouldn't rely on it.

5 Comments

Enter at least 15 characters
    Mawg
Aaargh! Sigh. Looks like it's time for me to learn how to thread. Presumably each thread creates a TCP clietn, sends the message (which it received as a paramter), gets a reply or catches an exception and then sends a windows message to the main form with the resule and destroys the TCP client? Hmm, can I get a unique thread Id for tracing porpoises?
Enter at least 15 characters
Enter at least 15 characters
    Mawg
Thanks, @David I'm diving into the world of threading now ;-)
Enter at least 15 characters
Enter at least 15 characters
The problem with putting close in a different thread is the lifetime management of the binding. If worker thread is closing the socket, you can't free the binding until it's done.
Enter at least 15 characters
Enter at least 15 characters
Indy does use a worker thread to make a connection, and if the thread does not terminate before the timeout then Indy closes the socket and waits for the thread to terminate. Are you suggesting that Indy use another thread to close the socket? I suppose Indy could create a thread but not wait on it, just let it run in the background and terminate itself when finished. That would require TIdSocketHandle relinquishing ownership of the socket handle and give it to the thread to free when ready...
Enter at least 15 characters
Enter at least 15 characters
... But there is still the issue of Indy having to wait for the connect thread to terminate, and if its still waiting for the close thread to actually close the socket, this doesn't solve anything.
Enter at least 15 characters
Enter at least 15 characters
Enter at least 15 characters
1

I've had same problems with INDY in the past (while using D6, year 1998-2000). I changed the component to IP*Works. At that time it was an external component, but as far as I know it is included in XE2. Ip*Works is a bit hard to understand at the beginning but the way they approach to the communication structure is a lot different.

I think that it would be worth to give it a try.

1 Comment

Enter at least 15 characters
    Mawg
When I find the time, I will give it a try. Thanks for the tip (although I don't, at first glance, see it in XE2)
Enter at least 15 characters
Enter at least 15 characters
Enter at least 15 characters

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.