views:

487

answers:

3

I am writing a little Comet server in C#, and to test it I have written a little program that opens a bunch of connections, writes a little text to each of them, and then closes each of them:

int basePort = 30000;
IPAddress localAddress = new IPAddress( new byte[] { 127, 0, 0, 1 } );
List<Socket> sockets = new List<Socket>();

for( int i = 0; i < 20000; i++ ) {
    Socket s = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
    s.Bind( new IPEndPoint( localAddress, basePort + i ) );
    s.Connect( "localhost", 1999 );
    sockets.Add( s );
}

string message = "hello";
byte[] messageData = Encoding.ASCII.GetBytes( message );
foreach( Socket s in sockets ) {
    s.Send( messageData );
}

foreach( Socket s in sockets ) {
    s.Disconnect( false );
}

I am using Windows XP at the moment, which only assigns dynamic client ports from the 1025 to 5000 range, so I have added explicit binding to ports starting at 30000. This took me from under 4000 connections to a little more than 16000, but now I am getting the following exception on Socket.Connect:

"An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full 127.0.0.1:1999"

Any thoughts? Changing the send and receive buffer size doesn't seem to make any difference, and it always seems to be my client app that breaks, never my server. I realize I'm going to run out of client ports before I get to 100,000 connections, but I'd still like to understand what is going on a little better.

+1  A: 

Windows XP (and other versions presumably) have limits on the number of open ports allowed at any one time. This MSDN article may be helpful in modifying the TcpIp parameters to increase the number of ports available and decrease the amount of time Windows holds the port open before it's allowed to be reused.

tvanfosson
I think I've got the port exhaustion stuff dealt with already. The explicit binding is there to deal with the limited number of dynamically assigned ports, and the Socket.Disconnect frees the socket a little faster than a Socket.Close, so I can re-run my test without waiting for the TIME_WAIT interval.
Daryl
I think that there's also a rate limit parameter, but I didn't find an MSDN reference for that. The other suspicion that I have is the number of network buffers available.
tvanfosson
You dont need explicit binding to deal with the dynamic limit, you just need to adjust the limit as tvanfosson suggested.
Len Holgate
+1  A: 

You might be running out of non-paged memory. There are per-machine and per-process limits which are based on the amount of installed RAM, OS, /3GB switch settings, etc. 32 bit OS skus' have a much lower limit on non-paged memory than 64 bit OS sku's.

dpp
That looked promising, but when my test client dies I'm using less than 28MB of nonpaged kernel memory. From what I've read, the system-wide limit should be at least 100MB. It looks like I'm not hitting the per-process limit either, because when the client dies it is using less than 8MB, while the server seems to be doing fine at over 10MB.
Daryl
+1  A: 

I think 100.000 connections is not a feasible goal.

TCP/IP ports are 16bit numbers. So anything above 65535 is a no go anyway.

Toad
Yeah, in the description I mention that I will run out of client ports before I get to 100,000, but I'd like to try and reach some hard limit like that before I give up.
Daryl
I've thought about this a little bit more. TCP/IP ports are actually addressed by ip and port, so I can use each port once for each ip address. Connecting to a local service I can use the local address ( 127.0.0.1 ) and the default external address, which gives me well over 100,000 different client endpoints. I have tested this and it works nicely on my Windows XP box.
Daryl
still, if you connect to some external or internal ip/port, it still needs a local ip/port combination too. e.g. say i connect to google.com:80 then a local port is allocated too. It is the localport combos where you run out of.So I don't understand how you can go above the 65536 limit.
Toad