2015-02-26 8 views
0

Итак, у меня есть куча разных портов, которые я хочу прослушивать, и перебирать доступные данные для отправки в конвейер потока данных. В целом я слушаю 14 портов. Ищите любые советы о том, как уменьшить использование процессора в следующем коде.Высокий udpclient cpu использует

Так что я просто проездом в портах к способу затем добавить их в список

public static void AddPorts(Dictionary<int,string> ports) 
    { 
     try 
     { 


       var NewEndPoints = new List<IPEndPoint>(); 
       foreach (var port in ports) 
       { 
        var endpoint = new IPEndPoint(IPAddress.Any, port.Key); 
        NewEndPoints.Add(endpoint); 
        if (!Endpoints.Contains(endpoint)) 
        {        
         Endpoints.Add(endpoint); 
         var client = new UdpClient(endpoint); 
         logger.Info("New Client added on port: {0}", endpoint.Port); 
         Clients.Add(client); 

        } 
        else 
        { 
         if (IgnoredPorts.Contains(endpoint.Port)) 
         { 
          logger.Info("Existing client enabled on port: {0}", endpoint.Port); 
          IgnoredPorts.Remove(port.Key); 
         } 
        } 
       } 
       var differences = Endpoints.Except(NewEndPoints); 
       differences.ToList().ForEach(d => 
       {       
        if (!IgnoredPorts.Contains(d.Port)) 
        { 
         IgnoredPorts.Add(d.Port); 
         logger.Info("Client removed on port: {0}", d.Port); 
        } 
       }); 



     } 
     catch (Exception ex) 
     { 
      logger.Error("Error creating udpclients", ex); 
     } 
    } 

Я тогда пошаговый просмотр всех доступных данных

Task.Run(async delegate 
     { 

      while (Receive) 
      { 
       try 
       { 
        // get any channels that have data availble 
        // Iterate over the the channels and send to Dataflow pipeline 
        var readyChannels = 
       (from channel in Clients 
       where channel.Available > 0 && !ListenersDF.IgnoredPorts.Contains(((IPEndPoint)channel.Client.LocalEndPoint).Port) 
       select channel); 

        // Iterate over the the channels and send to Dataflow pipeline 
        foreach (var channel in readyChannels) 
        { 
         // await on the result of the task 
         await ReceiveAndRespond(channel); 
        } 

       } 
       catch (Exception ex) 
       { 
        logger.Error("Error sending packet to bufferBlock", ex); 
       } 
      } 
     }); 

И, наконец, отправить его в поток данных pipline

async Task ReceiveAndRespond(UdpClient channel) 
    { 
     UdpReceiveResult? result = null; 

     try 
     { 
      result = await channel.ReceiveAsync(); 
     } 
     catch (Exception exc) 
     { 
      logger.Error("Error receiving from channel: " + exc.Message, exc); 
     } 

     if (result != null) 
     { 
      var device = (from d in Ports 
          where d.Key == ((IPEndPoint)channel.Client.LocalEndPoint).Port 
          select d.Value).FirstOrDefault(); 
      UdpData data = new UdpData() { Client = channel, Data = result.Value.Buffer, LocalPort = ((IPEndPoint)channel.Client.LocalEndPoint).Port, LocalIP = ((IPEndPoint)channel.Client.LocalEndPoint).Address, RemoteEndpoint = result.Value.RemoteEndPoint, Device = device }; 
      Flow.bufferBlock.Post(data); 

      // for testing logs the hex string to a log file    
      //logger.Warn(string.Format("Data received on port: {0} for device: {1} with data: {2}", data.LocalPort, data.Device, data.Data.ByteArrayToHexString()));    
     } 
    } 

Тогда cpu сидит на 50% с трудом и трафиком, и я уверен, что что-то случилось о том, как я это делаю. Любая помощь очень ценится!

+0

В цикле 'в то время (Receive)', вы проверяете и проверить и проверить 'где channel.Available> 0', принимая во внимание скорость CPU, вы в основном проверяете, не делая ничего. – EZI

+0

Любой лучший способ получить данные из каналов с данными, готовыми к приему? – Jesse

ответ

1

Думаю, вы должны изменить свой дизайн. Вот пример кода сервера.

public class UDPServer 
{ 
    public UDPServer(IEnumerable<int> listenPorts) 
    { 
     foreach(var port in listenPorts) 
     { 
      var udpClient = new System.Net.Sockets.UdpClient(); 
      udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, port)); 
      udpClient.BeginReceive(Receive, udpClient); 
     } 
    } 

    public void Receive(IAsyncResult ar) 
    { 
     var udpClient = ar.AsyncState as UdpClient; 
     IPEndPoint endPoint = null; 
     var data = udpClient.EndReceive(ar, ref endPoint); 

     //Do some work and send a response back 
     var dataToSend = Encoding.UTF8.GetBytes(String.Concat(Encoding.UTF8.GetString(data).Reverse())); 
     udpClient.Client.SendTo(dataToSend, endPoint); 

     udpClient.BeginReceive(Receive, udpClient); 
    } 
} 

Теперь вы можете проверить это следующим образом:

var server = new UDPServer(new[] { 10000, 10001, 10002 }); 
await Task.Delay(2000); //Just to keep the code simple, for now. 

var udpClient = new UdpClient(); 
udpClient.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 10001)); 

while (true) 
{ 
    var line = Console.ReadLine(); 
    if (line == ".") break; 

    var data = Encoding.UTF8.GetBytes(line); 
    udpClient.Send(data, data.Length); 

    IPEndPoint endPoint = null; 
    var recvData = udpClient.Receive(ref endPoint); 
    Console.WriteLine(Encoding.UTF8.GetString(recvData)); 
} 
+0

Какова ценность UDPServer? Вы не используете в тесте? Я вижу, где вы собираетесь с этим. Я только сейчас уверен, как постоянно контактировать с клиентами UDPServer и получать результат для обработки с помощью этого дизайна. – Jesse

+0

Вы пытались проверить это? Я потратил свое время и подготовил ** рабочий код **. Просто создайте консольное приложение и скопируйте и вставьте. Вы слишком заняты? – EZI

+0

Я, как мы говорим, спасибо – Jesse