【问题标题】:How to write a .Net UDP Scalable server如何编写 .Net UDP 可扩展服务器
【发布时间】:2011-04-29 21:28:46
【问题描述】:

我需要编写一个负载很高的 UDP 服务器。我正在使用.Net。如何使用 Socket 类来实现这一点?

我熟悉 winsock API 和完成端口,我会在那里做的是使用多个线程通过完成端口接受套接字,并以相同的方式接收。

我的服务器需要非常快速地处理大量的小型 UDP 数据包,我想异步接收它们,我如何使用 .net 来做到这一点?

我想过多次调用 BeginReceive,但这似乎有点傻......

如果有人对此有一个好的 .net 示例,那当然会有很大帮助。

【问题讨论】:

    标签: c# .net sockets networking udp


    【解决方案1】:

    我发现最小化丢弃数据包的方法是从套接字异步读取您提到的,但是将读取的字节放入线程安全队列,然后让另一个线程从队列中读取并处理字节。如果您使用的是 .Net 4.0,则可以使用 ConcurrentQueue:

    public class SomeClass {
        ConcurrentQueue<IList<Byte>> _Queue;
        Byte[] _Buffer;
        ManualResetEvent _StopEvent;
        AutoResetEvent _QueueEvent;
        private void ReceiveCallback(IAsyncResult ar) {
            Socket socket = ar.AsyncState as Socket;
            Int32 bytesRead = socket.EndReceive(ar);
            List<Byte> bufferCopy = new List<byte>(_Buffer);
            _Queue.Enqueue(bufferCopy);
            _QueueEvent.Set();
            if(!_StopEvent.WaitOne(0)) socket.BeginReceive(...);
            return;
        }
        private void ReadReceiveQueue() {
            WaitHandle[] handles = new WaitHandle[] { _StopEvent, _QueueEvent };
            Boolean loop = true;
            while (loop) {
                Int32 index = WaitHandle.WaitAny(handles);
                switch (index) {
                    case 0:
                        loop = false;
                        break;
                    case 1:
                        // Dequeue logic here
                        break;
                    default:
                        break;
                }
            }
        }
    }
    

    注意:_StopEvent 是 ManualResetEvent,因此 ReceiveCallback 和 ReadReceiveQueue 方法可以使用相同的事件干净地关闭。

    【讨论】:

    • 这是一个有问题的方法,如果你有一个恒定的高负载,我没有任何好处,并且很难正确管理队列(从套接字读取处理速度要快得多)。
    【解决方案2】:

    如果您只有一个套接字并且可以彼此独立地处理 UDP 数据包,那么最好的方法实际上是使用线程池,其中每个线程调用阻塞接收。操作系统将负责唤醒等待线程之一以接收/处理数据包。这样您就可以避免异步 I/O 例程引入的任何开销。

    【讨论】:

    • 这是一种适用于中等负载情况的有效方法。但是创建大量线程引起的开销会影响您的性能和可扩展性。
    • 但您不会创建大量线程 - 线程池的大小大致取决于 CPU 内核的数量。
    猜你喜欢
    • 1970-01-01
    • 2010-10-26
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    • 2019-01-25
    相关资源
    最近更新 更多