Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

TCP/IP Parameter Tuning for Rapid Client Connections

2.00/5 (2 votes)
22 Feb 2010CPOL4 min read 1   704  
Applications that open and close a large number of client TCP/IP sockets run the risk of running out of available socket ports. The exceptions raised can be misleading because they are generally associated with server socket conflicts – not outbound client connections.

Latest Source Code

In addition to the links above, you can also download the latest code from the link below to ensure you have the most current version:

Introduction

I recently shared my experiences troubleshooting a curious problem of port conflicts when opening client socket connections[^]. Applications that open and close a large number of client TCP/IP sockets run the risk of running out of available socket ports. This can happen in a load and performance testing scenario using a tool like LISA Test from iTKO[^], or it could happen in a production environment if an active application simply needs to rapidly open and close a large number of outbound connections.

On the .NET platform, the exception raised reads:

"System.Net.Sockets.SocketException: Only one usage of each socket address
(protocol/network address/port) is normally permitted <host>:<port>".

In Java, the exception is:

"java.net.BindException: Address already in use: connect".

Both exceptions are misleading because they are generally associated with server socket conflicts – not outbound client socket connections. However, a better understanding of the TCP state machine sheds some light on this behavior - and a solution.

Common Port Conflict Exceptions

Whenever TCP/IP encounters a port conflict, you can expect one of the two following exceptions to be thrown depending upon your environment:

In a C# environment, you'll see this exception:

System.Net.Sockets.SocketException: Only one usage of each socket address
(protocol/network address/port) is normally permitted <host>:<port>

In Java, you'll see this:

Java
java.net.BindException: Address already in use: connect
   at java.net.PlainSocketImpl.socketConnect(Native Method)
   at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333)
   at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195)
   at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182)
   at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
   at java.net.Socket.connect(Socket.java:519)
   at java.net.Socket.connect(Socket.java:469)

If you see these exceptions thrown when a server socket attempts to listen for incoming connections, the cause is obvious: the port you're attempting to listen on is already in use. For example, if you bring up a Web server, but another Web server is already running, an exception will be thrown because port 80 (or 8080) is already listening on behalf of another thread or application.

These exceptions are often confusing, however, when thrown setting up a client connection. Client TCP connections are always assigned an OS-selected port on the local side, so why is the operating system selecting an active port? The truth is the exception indicates no local port numbers are available to the client. This misreporting of the error by the OS is half the confusion.

Tuning Local Client Port Range

The problem is two-fold. First, Linux and Windows make only a certain number of ports available to client sockets – the default is in the range of 1024 to 5000. Hence, you may have only 3,976 active client connections at a time. For most systems, this is plenty. However, in specific circumstances on systems requiring a large number of outbound connections, this limit can be exhausted.

This range, however, can be tuned. On Windows, the upper bound for client port assignments can be adjusted using the MaxUserPort DWORD value on this registry key:

HKLM\System\CurrentControlSet\Services\Tcpip\Parameters

Of course, rather than using the cumbersome regedit, you can download IPtuner from this article to quickly set MaxUserPort as shown here:

Set MaxUserPort

On Linux, both the lower and upper bounds can be set using the following parameter:

net.ipv4.ip_local_port_range = 32768 65534

How this parameter is set in Linux varies depending upon the flavor and version of Linux you're using – and you'll need to restart networking after you change it.

Tuning TCP TIME_WAIT Timeout Value

The second cause of these exceptions has to do with the TCP state model and the way sockets are closed. Even after a socket has officially been "closed", it hangs around in a TIME_WAIT state as a safety mechanism to deal with stray packets. The default wait time on all operating systems, generally, is ridiculously long (240 seconds on Windows). So, even if an application doesn't require a lot of concurrent connections, it can still run out of available ports in a high load situation. If even one connection is repeatedly opened and closed fast enough, you'll soon have all available local sockets hanging around in a TIME_WAIT state and none available for new clients.

The TIME_WAIT state duration, however, is also tunable.

On Windows, using the same registry key, the TCPTimedWaitDelay value can be used to adjust the TIME_WAIT duration from 30 to 300 seconds. Once again, instead of fumbling through regedit, you can download IPtuner from this article to quickly set TCPTimedWaitDelay as shown here:

Set TCPTimedWaitDelay

On Linux, the wait delay is configured using the following parameter:

net.ipv4.tcp_fin_timeout = 30

By decreasing the TCP wait delay, closed sockets spend less time in the TIME_WAIT state and get returned to the pool of available client ports faster. However, to avoid communication problems, do not lower this value below 30 seconds.

Administrator Privileges Required

On both Linux and Windows (even if using IPtuner or regedit), you'll require administrator privileges to change these parameters. However, anyone can view these settings to at least verify if they make sense.

History

  • 22nd February, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)