简体   繁体   中英

TCP socket sharding in .NET

I'm trying to write a high-performance HTTP server in C# without using third-party libraries, and during my readings, I foundthis 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?

On Windows, the SO_REUSEADDR option has no use cases for an HTTP server. It's only real use case is for multicast sockets where data is delivered to all of the sockets bound on the same port.

I suggest this SO post for a indepth discussion. How do SO_REUSEADDR and SO_REUSEPORT differ?

Under Windows with IOCP you don't need the Linux/Unix equivalent which can provide load balancing across multiple threads. IOCP takes care of this for you. The implementation is very different but achieves the same highly scalable result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM