C# 如何编写.Net UDP可扩展服务器

C# 如何编写.Net UDP可扩展服务器,c#,.net,sockets,networking,udp,C#,.net,Sockets,Networking,Udp,我需要写一个非常高负载的UDP服务器。我正在使用.Net。如何使用Socket类来实现这一点 我熟悉winsock API和完成端口,在那里我要做的是使用多个线程来接受使用完成端口的套接字,并以相同的方式接收 我的服务器需要非常快速地处理很多小的UDP数据包,我希望异步接收它们,我如何使用.net来实现这一点 我好几次想给BeginReceive打电话,但那似乎有点傻 如果有人有一个很好的.net示例,当然会有很大帮助。我发现,要最大限度地减少丢弃的数据包,可以像您提到的那样异步从套接字读取数据

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

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

我的服务器需要非常快速地处理很多小的UDP数据包,我希望异步接收它们,我如何使用.net来实现这一点

我好几次想给BeginReceive打电话,但那似乎有点傻


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

我发现,要最大限度地减少丢弃的数据包,可以像您提到的那样异步从套接字读取数据,但要将读取的字节放入线程安全队列,然后让另一个线程从队列中读取并处理字节。如果您使用的是.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;
            }
        }
    }
}
公共类SomeClass{
ConcurrentQueue\u队列;
字节[]_缓冲区;
手动复位事件_停止事件;
自动事件(AutoResetEvent)队列事件;;
私有void ReceiveCallback(IAsyncResult ar){
Socket Socket=ar.asynchstate作为Socket;
Int32字节读取=socket.EndReceive(ar);
List bufferCopy=新列表(_Buffer);
_排队(bufferCopy);
_QueueEvent.Set();
if(!\u StopEvent.WaitOne(0))socket.BeginReceive(…);
返回;
}
私有void ReadReceiveQueue(){
WaitHandle[]handles=新的WaitHandle[]{{u StopEvent,{u QueueEvent};
布尔循环=真;
while(循环){
Int32 index=WaitHandle.WaitAny(句柄);
开关(索引){
案例0:
循环=假;
打破
案例1:
//在此退出队列逻辑
打破
违约:
打破
}
}
}
}

注意:_StopEvent是一个ManualResetEvent,因此ReceiveCallback和ReadReceiveQueue方法都可以使用同一事件完全关闭。

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

对于中等负载情况,这是一种有效的方法。但是,创建大量线程所带来的开销会妨碍您的性能和可扩展性。但您不会创建大量线程-线程池的大小大致取决于CPU内核的数量。这是一种有问题的方法,如果您的负载一直很高,我不会给您带来任何好处,而且很难正确管理队列(从套接字读取数据的处理速度要快得多)。