2012-02-22 12 views
8

Estamos desarrollando una aplicación que se instalará en la PC y realizará algunas cargas y descargas en segundo plano a/desde nuestro servidor. Uno de los requisitos es detectar si la conexión a Internet está actualmente ocupada (por ejemplo, por encima del 50% de utilización) y si es así, debe retroceder e intentar en otro momento. La razón principal es asegurarse de que la aplicación no interfiera con la experiencia del usuario si están en medio de un juego, viendo una película en línea o descargando agresivamente archivosDetectando si la conexión a Internet está ocupada

Después de mucho pensar e investigar en Google y, por supuesto, SO, aún no lo he hecho Encontré una buena manera de cómo implementar esto, así que decidí lanzar esto aquí. La aplicación se implementa en C#, .NET 4.0 y estoy buscando todas las formas de respuestas, ya sea implementación en C# u otros lenguajes, pseudo-lógica o enfoque sobre cómo lograr, medición de la utilización del tráfico de Internet en PC local con buena suficiente precisión.

Para evitar la duplicación de esfuerzos, hasta ahora he tratado estos (y por qué no son adecuados)

  • utilizar WMI para obtener estadística de la red. La mayoría de las publicaciones y soluciones de SO existen porque este enfoque no cumple con nuestros requisitos ya que la medición de los bytes enviados/recibidos contra la capacidad de la interfaz de red (p. Ej., La tarjeta Ethernet de 1GB) será una buena medida para el tráfico de LAN. pero no para el tráfico de Internet (donde el ancho de banda real Internet sólo se podría decir 8 Mbps)
  • el uso de .NET Estadísticas de red de información o contador de rendimiento - rendimiento de lecturas similares a los anteriores, por lo tanto tienen las mismas deficiencias
  • uso de ICMP (ping) y mide RTT. Se sugirió que 400ms RTT se considera una indicación lenta y buena para la red ocupada, sin embargo, me dijeron que el usuario con módem (sí, tenemos que admitir eso), el uso del proxy inverso o el enlace de microondas a menudo hacen ping por encima de eso. medida
  • Comience a descargar un archivo conocido y mida la velocidad; esto generará tráfico que estamos tratando de evitar, y si este control se realiza con suficiente frecuencia, nuestra aplicación terminará creando mucho tráfico de Internet, lo que tampoco es ideal.
  • MOD: el uso de BITS - este servicio se puede desactivar en el PC del usuario, exige cambios en la política de grupo y asumen servidor para IIS (con configuración personalizada) y en nuestro caso nuestro servidor IIS no es

Así que aquí está, estoy confundido y estoy buscando algún consejo. Destaqué el texto de la pregunta para que ustedes no se pierdan al leer esto y se pregunten cuál es la pregunta. Gracias.

+0

La solución correcta sería QoS en el enrutador. Lástima que la mayoría de los enrutadores de consumo son una mierda. – CodesInChaos

+1

Parece un problema común, pero no parece una solución común :( –

+1

Porque el problema es imposible de resolver en el nivel de la PC. Su software no puede saber cuánto tráfico está produciendo otra persona, usando el mismo enrutador. – CodesInChaos

Respuesta

5

Puede usar UPnP para consultar el enrutador y recuperar el número de bytes enviados y recibidos a través de la red. Puede seguir comprobando este valor en el enrutador para determinar cuál es la actividad. Desafortunadamente, esta funcionalidad no parece estar bien documentada, pero es posible implementar la funcionalidad de comunicación UPnP dentro de una aplicación C#. Tendrá que usar UDP para consultar el enrutador (UPnP discover), y una vez que haya encontrado el dispositivo, consultar su funcionalidad y luego consultar el número de paquetes enviados y recibidos para el Dispositivo de Internet Gateway utilizando un WebClient (TCP).

 
Code for a UPnP library: 

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Net.Sockets; 
using System.Net; 
using System.Xml; 
using System.IO; 
namespace UPNPLib 
{ 
    public class RouterElement 
    { 
     public RouterElement() 
     { 
     } 
     public override string ToString() 
     { 
      return Name; 
     } 
     public List children = new List(); 
     public RouterElement parent; 
     public string Name; 
     public string Value; 
     public RouterElement this[string name] { 
      get 
      { 
       foreach (RouterElement et in children) 
       { 
        if (et.Name.ToLower().Contains(name.ToLower())) 
        { 
         return et; 
        } 
       } 
       foreach (RouterElement et in children) 
       { 
        Console.WriteLine(et.Name); 
       } 
       throw new KeyNotFoundException("Unable to find the specified entry"); 
      } 
    } 
     public RouterElement(XmlNode node, RouterElement _parent) 
     { 

      Name = node.Name; 
      if (node.ChildNodes.Count 
     /// Gets the root URL of the device 
     /// 
     /// 
     public static string GetRootUrl() 
     { 
      StringBuilder mbuilder = new StringBuilder(); 
      mbuilder.Append("M-SEARCH * HTTP/1.1\r\n"); 
      mbuilder.Append("HOST: 239.255.255.250:1900\r\n"); 
      mbuilder.Append("ST:upnp:rootdevice\r\n"); 
      mbuilder.Append("MAN:\"ssdp:discover\"\r\n"); 
      mbuilder.Append("MX:3\r\n\r\n"); 
      UdpClient mclient = new UdpClient(); 
      byte[] dgram = Encoding.ASCII.GetBytes(mbuilder.ToString()); 
      mclient.Send(dgram,dgram.Length,new IPEndPoint(IPAddress.Broadcast,1900)); 
      IPEndPoint mpoint = new IPEndPoint(IPAddress.Any, 0); 
      rootsearch: 

      dgram = mclient.Receive(ref mpoint); 
      string mret = Encoding.ASCII.GetString(dgram); 
      string orig = mret; 
      mret = mret.ToLower(); 
      string url = orig.Substring(mret.IndexOf("location:") + "location:".Length, mret.IndexOf("\r", mret.IndexOf("location:")) - (mret.IndexOf("location:") + "location:".Length)); 
      WebClient wclient = new WebClient(); 
      try 
      { 
       Console.WriteLine("POLL:" + url); 
       string reply = wclient.DownloadString(url); 

       if (!reply.ToLower().Contains("router")) 
       { 
        goto rootsearch; 
       } 
      } 
      catch (Exception) 
      { 
       goto rootsearch; 
      } 
      return url; 
     } 
     public static RouterElement enumRouterFunctions(string url) 
     { 

      XmlReader mreader = XmlReader.Create(url); 
      XmlDocument md = new XmlDocument(); 
      md.Load(mreader); 
      XmlNodeList rootnodes = md.GetElementsByTagName("serviceList"); 
      RouterElement elem = new RouterElement(); 
      foreach (XmlNode et in rootnodes) 
      { 
       RouterElement el = new RouterElement(et, null); 
       elem.children.Add(el); 
      } 

      return elem; 
     } 
     public static RouterElement getRouterInformation(string url) 
     { 
      XmlReader mreader = XmlReader.Create(url); 
      XmlDocument md = new XmlDocument(); 
      md.Load(mreader); 
      XmlNodeList rootnodes = md.GetElementsByTagName("device"); 
      return new RouterElement(rootnodes[0], null); 
     } 

    } 
    public class RouterMethod 
    { 
     string url; 
     public string MethodName; 
     string parentname; 
     string MakeRequest(string URL, byte[] data, string[] headers) 
     { 
      Uri mri = new Uri(URL); 
      TcpClient mclient = new TcpClient(); 
      mclient.Connect(mri.Host, mri.Port); 
      Stream mstream = mclient.GetStream(); 
      StreamWriter textwriter = new StreamWriter(mstream); 
      textwriter.Write("POST "+mri.PathAndQuery+" HTTP/1.1\r\n"); 

      textwriter.Write("Connection: Close\r\n"); 

      textwriter.Write("Content-Type: text/xml; charset=\"utf-8\"\r\n"); 

      foreach (string et in headers) 
      { 
       textwriter.Write(et + "\r\n"); 
      } 
      textwriter.Write("Content-Length: " + (data.Length).ToString()+"\r\n"); 
      textwriter.Write("Host: " + mri.Host+":"+mri.Port+"\r\n"); 


      textwriter.Write("\r\n"); 
      textwriter.Flush(); 



      Stream reqstream = mstream; 
      reqstream.Write(data, 0, data.Length); 
      reqstream.Flush(); 
      StreamReader reader = new StreamReader(mstream); 
      while (reader.ReadLine().Length > 2) 
      { 

      } 
      return reader.ReadToEnd(); 
     } 
     public RouterElement Invoke(string[] args) 
     { 

      MemoryStream mstream = new MemoryStream(); 
      StreamWriter mwriter = new StreamWriter(mstream); 
      //TODO: Implement argument list 
      string arglist = ""; 

      mwriter.Write("" + "" + ""); 


      mwriter.Write("");//" + arglist + ""); 
      mwriter.Write(""); 
      mwriter.Flush(); 

      List headers = new List(); 

      headers.Add("SOAPAction: \"" + parentschema + "#" + MethodName + "\""); 

      mstream.Position = 0; 
      byte[] dgram = new byte[mstream.Length]; 

      mstream.Read(dgram, 0, dgram.Length); 

      XmlDocument mdoc = new XmlDocument(); 
      string txt = MakeRequest(url, dgram, headers.ToArray()); 
      mdoc.LoadXml(txt); 
      try 
      { 
       RouterElement elem = new RouterElement(mdoc.ChildNodes[0], null); 

       return elem["Body"].children[0]; 
      } 
      catch (Exception er) 
      { 
       RouterElement elem = new RouterElement(mdoc.ChildNodes[1], null); 
       return elem["Body"].children[0]; 
      } 

     } 
     public List parameters = new List(); 
     string baseurl; 
     string parentschema; 
     public RouterMethod(string svcurl, RouterElement element,string pname, string baseURL, string svcpdsc) 
     { 
      parentschema = svcpdsc; 
      baseurl = baseURL; 
      parentname = pname; 
      url = svcurl; 
      MethodName = element["name"].Value; 
      try 
      { 
       foreach (RouterElement et in element["argumentList"].children) 
       { 
        parameters.Add(et.children[0].Value); 
       } 
      } 
      catch (KeyNotFoundException) 
      { 
      } 
     } 
    } 
    public class RouterService 
    { 
     string url; 
     public string ServiceName; 
     public List methods = new List(); 
     public RouterMethod GetMethodByNonCaseSensitiveName(string name) 
     { 
      foreach (RouterMethod et in methods) 
      { 
       if (et.MethodName.ToLower() == name.ToLower()) 
       { 
        return et; 
       } 
      } 
      throw new KeyNotFoundException(); 
     } 
     public RouterService(RouterElement element, string baseurl) 
     { 

      ServiceName = element["serviceId"].Value; 
      url = element["controlURL"].Value; 

      WebClient mclient = new WebClient(); 
      string turtle = element["SCPDURL"].Value; 
      if (!turtle.ToLower().Contains("http")) 
      { 
       turtle = baseurl + turtle; 
      } 
      Console.WriteLine("service URL " + turtle); 
      string axml = mclient.DownloadString(turtle); 
      XmlDocument mdoc = new XmlDocument(); 
      if (!url.ToLower().Contains("http")) 
      { 
       url = baseurl + url; 
      } 
      mdoc.LoadXml(axml); 
      XmlNode mainnode = mdoc.GetElementsByTagName("actionList")[0]; 
      RouterElement actions = new RouterElement(mainnode, null); 
      foreach (RouterElement et in actions.children) 
      { 
       RouterMethod method = new RouterMethod(url, et,ServiceName,baseurl,element["serviceType"].Value); 
       methods.Add(method); 
      } 

     } 
    } 
} 

 
 

Code for a bandwidth meter: 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
using UPNPLib; 
using System.IO; 

namespace bandwidthmeter 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      BinaryReader mreader = new BinaryReader(File.Open("bandwidthlog.txt", FileMode.OpenOrCreate)); 
      if (mreader.BaseStream.Length > 0) 
      { 
       prevsent = mreader.ReadInt64(); 
       prevrecv = mreader.ReadInt64(); 
      } 
      mreader.Close(); 
      List services = new List(); 
      string fullurl = UPNP.GetRootUrl(); 
      RouterElement router = UPNP.enumRouterFunctions(fullurl); 
      Console.WriteLine("Router feature enumeration complete"); 
      foreach (RouterElement et in router.children) 
      { 

       services.Add(new RouterService(et.children[0], fullurl.Substring(0, fullurl.IndexOf("/", "http://".Length+1)))); 
      } 
      getReceiveDelegate = services[1].GetMethodByNonCaseSensitiveName("GetTotalBytesReceived"); 
      getSentDelegate = services[1].GetMethodByNonCaseSensitiveName("GetTotalBytesSent"); 
      Console.WriteLine("Invoking " + getReceiveDelegate.MethodName); 
      //Console.WriteLine(services[1].GetMethodByNonCaseSensitiveName("GetTotalPacketsSent").Invoke(null)); 

      Timer mymer = new Timer(); 
      mymer.Tick += new EventHandler(mymer_Tick); 
      mymer.Interval = 1000; 
      mymer.Start(); 
      FormClosed += new FormClosedEventHandler(Form1_FormClosed); 
     } 
     long prevsent = 0; 
     long prevrecv = 0; 
     void Form1_FormClosed(object sender, FormClosedEventArgs e) 
     { 
      BinaryWriter mwriter = new BinaryWriter(File.Open("bandwidthlog.txt", FileMode.OpenOrCreate)); 
      mwriter.Write(getsent()); 
      mwriter.Write(getreceived()); 
      mwriter.Flush(); 
      mwriter.Close(); 

     } 
     long getsent() 
     { 
      long retval = Convert.ToInt64(getSentDelegate.Invoke(null).children[0].Value); 
      if (prevsent > retval) 
      { 
       retval = prevsent + retval; 
      } 
      return retval; 
     } 
     long getreceived() 
     { 
      long retval = Convert.ToInt64(getReceiveDelegate.Invoke(null).children[0].Value); 
      if (prevrecv > retval) 
      { 
       retval = prevrecv + retval; 
      } 
      return retval; 
     } 
     void mymer_Tick(object sender, EventArgs e) 
     { 
      label1.Text = "Sent: "+(getsent()/1024/1024).ToString()+"MB\nReceived: "+(getreceived()/1024/1024).ToString()+"MB"; 

     } 
     RouterMethod getSentDelegate; 
     RouterMethod getReceiveDelegate; 

    } 
} 
 
+0

Gracias por la respuesta. ¿Funcionará este enfoque con todos los Win OS compatibles y la mayoría de los enrutadores? También una vez que recibo el paquete enviado y recibido, cómo hacerlo para determinar la utilización (como en mi ejemplo> 50% es considerado ocupado) –

+0

Sí, este enfoque funcionará con la mayoría de los enrutadores de consumo, pero no con los de negocios (UPnP es deshabilitado por defecto en los enrutadores corporativos). – IDWMaster

+0

Lea este artículo - http://www.codeproject.com/Articles/27992/NAT-Traversal-with-UPnP-in-C para obtener una introducción a UPnP. Esta muestra está pensada para el reenvío de puertos, pero puede usar las URL que proporciona el enrutador para buscar sus otras funciones (las funciones de ancho de banda suelen ser las mismas en la mayoría de los enrutadores). – IDWMaster

4

Ha considerado el uso Background Intelligent Transfer Service (BITS).Está diseñado para hacer este trabajo ya:

El Servicio de transferencia inteligente en segundo plano (BITS) transfiere archivos (descargas o cargas) entre un cliente y servidor y proporciona información de progreso relacionada con las transferencias. También puede descargar archivos de un compañero.

y,

preservar la capacidad de respuesta de otras aplicaciones de red.

No estoy seguro de si hay una interfaz administrada (puedo ver la referencia a los cmdlets Powershell), por lo que es posible que tenga que usar interoperabilidad COM para usarlo.

+0

Sí, pero lamentablemente no satisface nuestras necesidades debido a varias razones: el servicio BITS se puede deshabilitar, requiere cambios de política de grupo y el punto final del servidor (se supone IIS) y necesita ser configurado; en nuestro caso, el servidor no está IIS. +1 para sugerencia. –

1

Suponiendo que se dirige a PC con Windows (como dijo que estaba desarrollando en C#), ¿ha mirado al BITS, el Servicio de transferencia inteligente en segundo plano?

Hay ejemplos de cómo enganchar con C# en MSDN y en otros lugares, p. http://msdn.microsoft.com/en-us/magazine/cc188766.aspx

+0

Gracias por los comentarios. Sí, lo hice, por favor vea mi respuesta a la respuesta de Damián que tocaba lo mismo. –

Cuestiones relacionadas