简体   繁体   English

.NET 中的 TCP 套接字分片

[英]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.我正在尝试在不使用第三方库的情况下用 C# 编写一个高性能的 HTTP 服务器,在阅读过程中,我在 nginx 博客上找到了这篇文章 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.那里提到的是使用 SO_REUESEPORT 但该选项在 .NET 套接字和 Windows 中不可用,因此我搜索了此选​​项的替代方法,并且我读过在 Windows 和 .NET 中都可用的 SO_REUSEADDR 是我的选项有找。

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.我试图通过创建 4 个套接字并在绑定套接字并开始侦听之前启用重用地址来实现这一点,但是之后发生的事情是只有一个套接字接受连接,即使其线程忙。

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?我做错了什么还是整个技巧在 Windows 和 .NET 中是不可能的?

On Windows, the SO_REUSEADDR option has no use cases for an HTTP server.在 Windows 上,SO_REUSEADDR 选项没有用于 HTTP 服务器的用例。 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.我建议这篇 SO post 进行深入讨论。 How do SO_REUSEADDR and SO_REUSEPORT differ? SO_REUSEADDR 和 SO_REUSEPORT 有何不同?

Under Windows with IOCP you don't need the Linux/Unix equivalent which can provide load balancing across multiple threads.在带有 IOCP 的 Windows 下,您不需要 Linux/Unix 等价物,它可以提供跨多个线程的负载平衡。 IOCP takes care of this for you. IOCP 会为您处理这些。 The implementation is very different but achieves the same highly scalable result.实现非常不同,但实现了相同的高度可扩展的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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