Writing High Performance Sockets in C#

Many unexperienced server coders believes the socket decides a large part of the server application performance behavior. On one side they are right, however, it is the overall performance which counts. Yet the socket is a part which many does not get how to use right and then "kills" the performance of the server applications. 

Blocking vs. non-blocking

The largest and most critical point when it comes to socket is determined if you chose blocking or non-blocking sockets. (Often referred to as non-async and async) A blocking send function means that the send function will have to wait for the data it sends to be sent before it is done calling the method. When it is a non-blocking, it means the send function is queued to the .NET thread pool, and when the data has been sent, it calls a callback method. A good example is a server application which is designed to hold tens of thousands of connections and respond to requests. If we had to use blocking methods, we would have to create one thread per individual connection which later on would not make the server application really scaleable. On the other hand, if we used non-blocking methods, no extra threads would have to be created since the .NET thread pool takes care of that for us. In addition to this, we would not have to wait for data to be received on each individual thread since callback objects takes care of that. 

Exception handling

Exception throwing and catching is expensive. When a connection is closed, it throws an exception if you are using the wrong methods or if you don't check if it is connected. One example on a connection that could throw an exception if it is closed:

private void StartSend(byte[] data, int dataLength)
{
	try
	{
		socket.BeginSend(data, 0, dataLength, 0, sendCallback, null);
	}
	catch 
	{
		Disconnect();
	}
}

There is no check if the connection is connected or if it is unable to send anything. In addition, it would throw an exception if the sending did not succeed. However, it can be avoided by using the following code:

private void StartSend(byte[] data, int dataLength)
{
	try
	{
		if (socket != null && socket.Connected)
		{
			SocketError error;
			socket.BeginSend(data, 0, dataLength, 0, out error, sendCallback, null);
		if (error != SocketError.Success && error != SocketError.IOPending)
			Disconnect();
	}
	else
	{
		Disconnect();
	}
}
catch 
{
	Disconnect();
}

}

This code checks if the connection is open and if the send method managed to send the data. If it failed, it tries to disconnect without throwing any exceptions.

Closing

Closing the connection is very important if we do not want our server to have tons of non-used connections which later on would time out. Closing the socket is fairly simple:

socket.Shutdown(SocketShutdown.Both);
socket.Dispose();

The shutdown method disables any send/receive on the socket. The Dispose is technically the same as Close, since the Close method simply casts the socket to an IDisposable and then call the Dispose method. By calling the Disposed function directly, we do not have to cast the socket in the Close method.

Memory allocation

The buffer created for receiving data can be a headache for those who does not know what happens under the hood in the socket. In fact, when calling BeginSend, there is created objects which allocates far more data than a data buffer with length = 1024. (System.Threading.Overlapped, Socket.OverlappedCache just to mention a few) However, you can avoid the allocation of the buffer by creating buffer-pools for it. 

Going further

Out from my own experience with the socket class, I have to make changes to the socket class itself in order to achieve better performance. Moving the code to C++ might be a good idea since I get far more power over the memory used by the server. The overhead caused by P/invoke would not be much higher compared to the current overhead since the current socket already calls native functions by using WinSock methods.