2012-02-22 2 views
8

Мы разрабатываем приложение, которое будет установлено на ПК, и оно будет выполнять загрузку и загрузку фона на наш сервер. Одним из требований является обнаружение того, что интернет-соединение в настоящее время занято (скажем, более 50% использования), и если это так, ему необходимо отступить и попробовать другое время. Основная причина заключается в том, чтобы приложение не мешало работе с пользователями, если они находятся в середине игр, смотрят онлайн-фильм или агрессивно загружают файлы.Обнаружение, если интернет-соединение занято

После долгих размышлений и исследований по Google и, конечно же, SO, t нашел хороший способ, как реализовать это, поэтому решил бросить это здесь. Приложение реализовано на C#, .NET 4.0, и я ищу все формы ответов - либо на C#, либо на других языках, псевдо-логику или подход к достижению - измерение использования интернет-трафика на локальном ПК с хорошим достаточная точность.

Во избежание дублирования усилий, до сих пор я пытался эти (и почему они не подходят)

  • Использование WMI, чтобы получить сетевой статистики. Большинство сообщений SO и решений там, поскольку ссылаются на это как на подход, но это не соответствует нашему требованию, поскольку измерение байтов, отправленных/полученных по пропускной способности сетевого интерфейса (например, 1 ГБ Ethernet-карты) для использования, даст хорошую меру для трафика ЛВС но не для интернет-трафика (где фактическая пропускная способность Интернета может быть всего лишь 8 Мбит/с)
  • Использование статистики сети .NET или счетчик производительности - аналогичные показания к вышеуказанному имеют те же недостатки
  • Использовать ICMP (Ping) и измерять RTT. Было высказано предположение, что 400 мс RTT считается медленным и хорошим показателем для занятой сети, однако мне сказали, что пользователь с модемом (да, мы должны это поддержать), использование обратного прокси или микроволнового канала часто вызывает пинг выше, что, следовательно, не является хорошим measure
  • Начать загрузку известного файла и измерить скорость - это само генерирует трафик, который мы пытаемся избежать, также если эта проверка выполняется достаточно часто, наше приложение в конечном итоге создаст много интернет-трафика - что опять же не идеально
  • MOD: Использование BITS - эта услуга может быть отключена пользователем ПК, требует изменений политики группы и предполагает сервер быть IIS (с пользовательской конфигурацией) и в нашем случае наш сервер не IIS

Так вот, я все смущаюсь и ищу совет. Я выделил текст вопроса, чтобы вы, ребята, не потерялись, прочитав это и задавшись вопросом, в чем вопрос. Благодарю.

+0

Правильным решением будет QoS на маршрутизаторе. Жаль, что большинство потребительских маршрутизаторов сосать. – CodesInChaos

+1

Похоже на общую проблему, но похоже, что нет общего решения :( –

+1

Поскольку проблема невозможна для решения на уровне ПК, ваше программное обеспечение не может знать, сколько трафика генерирует кто-то другой, используя тот же маршрутизатор. – CodesInChaos

ответ

5

Вы можете использовать UPnP для запроса маршрутизатора и получить количество байтов, отправленных и полученных по сети. Вы можете продолжать проверять это значение на маршрутизаторе, чтобы определить, что такое активность. К сожалению, эта функциональность не выглядит хорошо документированной, но возможно реализовать коммуникационные функции UPnP в приложении C#. Вам нужно будет использовать UDP для запроса маршрутизатора (UPnP Discover), и как только вы найдете устройство, запросите его функциональность и затем запросите количество пакетов, отправленных и полученных для устройства интернет-шлюза, с помощью 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

Спасибо за ответ. Будет ли этот подход работать со всеми поддерживаемыми ОС Windows и большинством маршрутизаторов? Также, как только я получаю пакет, который был отправлен и получен, как мне сделать об определении использования (например, в моем примере> 50% считается занятым) –

+0

Да, этот подход будет работать с большинством потребительских маршрутизаторов, но не для большинства бизнес-приложений (UPnP отключено по умолчанию на корпоративных маршрутизаторах). – IDWMaster

+0

Прочтите эту статью - http://www.codeproject.com/Articles/27992/NAT-Traversal-with-UPnP-in-C для введения в UPnP. Этот пример предназначен для перенаправления портов, но вы можете использовать URL-адреса, которые маршрутизатор предоставляет для поиска своих других функций (функции пропускной способности обычно одинаковы для большинства маршрутизаторов). – IDWMaster

4

Рассматривали ли вы с помощью Background Intelligent Transfer Service (BITS).Он предназначен для этой работы уже:

Фоновая интеллектуальная служба передачи (BITS) передает файлы (загрузки или выгрузки) между клиентом и сервером и предоставляет информацию о ходе, связанной с переводами. Вы также можете загружать файлы со сверстников.

и

Сохранение других сетевых приложений.

Я не уверен, что есть управляемый интерфейс (я могу видеть ссылку на командлеты Powershell), поэтому вам, возможно, придется использовать COM-взаимодействие для его использования.

+0

Да, но, к сожалению, это не соответствует нашей потребности по нескольким причинам: услуга BITS может быть отключена, для нее требуются изменения групповой политики и конечная точка сервера (предполагается IIS), и ее необходимо настроить - в нашем случае сервер isn IIS. +1 за предложение. –

1

Предполагая, что вы нацеливаете компьютер с ОС Windows (как вы сказали, вы разрабатываете на C#), просмотрели ли вы BITS, Фоновая интеллектуальная служба передачи?

Есть примеры того, как подключиться к нему с помощью C# на MSDN и в другом месте, например. http://msdn.microsoft.com/en-us/magazine/cc188766.aspx

+0

Спасибо за отзыв. Да, я имею, пожалуйста, см. Мой ответ на ответ Дэмиена, который коснулся того же самого. –