I'm trying to write a high-performance HTTP server in C# without using third-party libraries, and during my readings, I found this post on nginx blog. What mentioned there is using SO_REUESEPORT but that option is not available in .NET sockets and also Windows, so I searched for an alternative to this option and I've read that SO_REUSEADDR which is available in both Windows and .NET is the option that I have looking for.
I have tried to implement that by creating 4 sockets and enabling reuse-address before binding the sockets and start listening, but what happens after is only one of the sockets accepts connections even though its thread goes busy.
static readonly byte[] Response = Encoding.ASCII.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r");
static int s_ListenerIndex = 0;
static void Main(string[] args)
{
var listenAddress = new IPEndPoint(IPAddress.Any, 26000);
var sockets = new Socket[4];
Console.WriteLine("Creating sockets");
for (int i = 0; i < sockets.Length; i++)
{
sockets[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sockets[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sockets[i].Bind(listenAddress);
}
Console.WriteLine("Starting listener threads");
for (int i = 0; i < sockets.Length; i++)
{
var socket = sockets[i];
CreateThread(() => ListenSocket(socket));
}
Thread.Sleep(Timeout.Infinite);
}
static void ListenSocket(Socket socket)
{
var listenerId = Interlocked.Increment(ref s_ListenerIndex);
socket.Listen(100);
Console.WriteLine($"Socket #{listenerId} is listening");
while (true)
{
Socket client = socket.Accept();
Console.WriteLine($"Socket #{listenerId} accepted connection");
client.Send(Response);
client.Close();
}
}
static void CreateThread(ThreadStart threadStart)
{
var thread = new Thread(threadStart);
thread.IsBackground = true;
thread.Start();
}
Am I doing something wrong or the whole trick is not possible in Windows and .NET?