2010-10-24 25 views
2

我需要編寫一個非常高負載的UDP服務器。我使用.Net。我如何使用Socket類實現這一目標?如何編寫.Net UDP可擴展服務器

我熟悉winsock API和完成端口,以及我在那裏要做的是使用幾個線程接受使用完成端口的套接字,並且也以相同的方式接收套接字。

我的服務器需要非常快速地處理很多小的UDP數據包,並且我想要異步接收它們,我如何使用.net來執行此操作?

我想調用BeginReceive幾次,但似乎有點傻......

如果任何人有一個很好的.NET示例,當然這將有很大的幫助。

回答

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方法可以使用相同的事件完全關閉。

+0

這是一個有問題的方法,如果你有一個恆定的高負載,並且很難正確管理隊列(從套接字讀取的處理速度要快得多),我不會給予任何好處。 – 2011-12-26 10:43:53

1

如果您只有一個套接字,並且您可以獨立處理UDP數據包,那麼最好的方法實際上就是使用線程池,其中每個線程都會調用一個阻塞接收。操作系統將負責喚醒其中一個等待線程來接收/處理數據包。這樣可以避免由異步I/O例程引入的任何開銷。

+0

這是適用於中等負載情況的有效方法。但創建大量線程所產生的開銷會妨礙您的性能和可伸縮性。 – 2011-12-26 10:40:55

+0

但是你不會創建大量的線程 - 線程池的大小將大致取決於CPU內核的數量。 – cmeerw 2013-02-07 13:26:50