I have a program which pulls a list of ip addresses from a database, around 3000 in total. Each address relates to a remote machine which should be running a .NET Remoting server to which my application is the client. I need to connect to each to pull back some data via .Net Remoting. However if there is some sort of problem at the remote site, there is a long wait until the program returns.
I have researched and found that I can check the .Net Remoting port before attempting a .Net Remoting connection by usin开发者_开发技巧g Sockets. Furthermore, with the async Socket.BeginConnect method, I can timeout any connections which don't return within a specified timeout period. This works great when I check one ip address at a time but for X number of addresses, this can potentially take (X * timeout) length of time to complete. So my next step was to introduce a threadpool so I could check multiple sites at the same time:
I create an OpenPortChecker object for each ip in a loop, supply it with a ManualResetEvent and the ip and then queue it in the threadpool. Once all have been added to the pool, I wait for all threads to complete by looping through the list of ManualResetEvents and calling WaitOne() on each. OpenPortChecker contains a method which performs a timed Socket.BeginConnect call to the specified ip as detailed above and then calls ManualResetEvent.Set() to signal when it has finished.
Yet this is not working as I anticipated: if I don't limit the threadpool size, all of the connections fail due to timeout (even though I know they are available) and eventually the program fails as too many threads are created. Infact, I can watch the number of threads in Task Manager go shooting up and up, even though each thread should only live for the specified timeout period before being returned to the pool. This can be solved by limiting the threadpool size but then the issue of time comes back into play. Additionally, unless I severley limit the pool (to around 10 threads) and set the timeout to 20 seconds, none of the connections are successful. This then becomes a balancing act between the number of threads and the timeout period which seems wrong and may fluctuate depending on the machine it is being run on. Infact, it is debateable if it is any better than checking one address at a time.
Am I limited in the number of connections I can make at once? Am I doing something wrong somewhere? Is there a better approach? Any help would be appreciated.
Thanks,
James
it seems that you have the tcpip.sys "half-open connections" limitation. if you have one of those operating system, you have that limitation:
- Windows XP Service Pack 2/3
- Windows 2003 Service Pack 1 and above
- Windows Vista/2008 Without Service Pack or with Service Pack 1.
- Windows 7 earlier than RTM.
To bypass this limitation:
- On Windows XP/2003 - Install 3rd party patch - http://www.lvllord.de
- On Windows Vista/2008 - Install Service Pack 2
- On Windows 7 - Install the RTM version.
As far as I know, the error is different when the remote site does not answer, when the remote site refuses connection and when connection could not be established due to some sort of outgoing connection quota. Bear in mind that simple network interface congestion might be the culprit and not any kind of quota.
Is non-blocking i/o available in c#? Then using one thread you can initiate several connection attempts, and get call-backs when they succeed or timeout.
Thanks for your replies. I have now resolved this issue so thought I'd post to share my answer should someone else face a similar problem. As Kieran Benton pointed out, there is a limit on the number of connections allowed by XP of 10 (cmd: net config server) so I have limited my program to run only ten threads at a time (although this still leaves a issue whereby a user may already be using some of the connection quota). Next, working with the information provided by Robert Obryk, I did some more research into Remoting connections and discovered that you can indeed set a timeout when making a remote connection via:
IDictionary prop = ChannelServices.GetChannelSinkProperties(remObject);
prop["timeout"] = remotingTimeout;
At this point, I dropped the initial timed Socket connection as it seemed this was no longer necessary, however testing showed that the Remoting timeout was only effective if the remote machine was reachable through the port specified. If the port was closed, the timeout was ignored and the connection hung. So my final implementation involves a timed Socket connection to first check that the port is open, then attempting a timed Remoting call to responsive sites. A bit long winded but it works!
Thanks again,
James
精彩评论