Comment calculer le trafic Internet entrant et sortant de HttpWebRequest

j'ai la fonction ci-dessous pour aller chercher une page. Ma question est que je veux calculer combien connexion internet est passé

trafic entrant (téléchargement) et trafic sortant (envoi)

Comment puis-je le faire ? Je vous remercie

Ma fonction

 public static string func_fetch_Page(string srUrl, int irTimeOut = 60,
    string srRequestUserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0",
    string srProxy = null)
    {
        string srBody = "";
        string srResult = "";
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(srUrl);

            request.Timeout = irTimeOut * 1000;
            request.UserAgent = srRequestUserAgent;
            request.KeepAlive = true;
            request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";

            WebHeaderCollection myWebHeaderCollection = request.Headers;
            myWebHeaderCollection.Add("Accept-Language", "en-gb,en;q=0.5");
            myWebHeaderCollection.Add("Accept-Encoding", "gzip, deflate");

            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

            using (WebResponse response = request.GetResponse())
            {
                using (Stream strumien = response.GetResponseStream())
                {
                    using (StreamReader sr = new StreamReader(strumien))
                    {
                        srBody = sr.ReadToEnd();
                        srResult = "success";
                    }
                }
            }
        }
        catch ()
        {

        }

        return srBody;
    }

C# .net 4.5 WPF application

@Simon Mourier comment calculer le trafic dépensé

public static long long_GlobalDownload_KByte = 0;
public static long long_GlobalSent_KByte = 0;

Time  _timer_fetch_download_upload = new Timer(getDownload_Upload_Values, null, 0, 100 * 1000);

public static void getDownload_Upload_Values(Object state)
{
    using (Process p = Process.GetCurrentProcess())
    {
        foreach (var cnx in TcpConnection.GetAll().Where(c => c.ProcessId == p.Id))
        {
            Interlocked.Add(ref long_GlobalDownload_KByte, Convert.ToInt64(cnx.DataBytesIn));
            Interlocked.Add(ref long_GlobalSent_KByte, Convert.ToInt64(cnx.DataBytesOut));
        }
    }
}
17
demandé sur MonsterMMORPG 2014-08-14 01:07:17

6 réponses

vous pouvez créer un proxy en utilisant FiddlerCore (juste une seule dll de référence) et d'un WebProxy pour votre HttpWebRequest compter les envoyés et reçus octets

public class WebConnectionStats
{
    static int _Read = 0;
    static int _Written = 0;

    public static void Init(bool registerAsSystemProxy = false)
    {
        Fiddler.FiddlerApplication.OnReadRequestBuffer += (s, e) => Interlocked.Add(ref _Written, e.iCountOfBytes);
        Fiddler.FiddlerApplication.OnReadResponseBuffer += (s, e) => Interlocked.Add(ref _Read, e.iCountOfBytes);
        Fiddler.FiddlerApplication.Startup(8088, registerAsSystemProxy, true);
    }

    public static int Read
    {
        get { return _Read; }
    }

    public static int Written
    {
        get { return _Written; }
    }
}

WebConnectionStats.Init(); //call this only once

var client = HttpWebRequest.Create("http://stackoverflow.com") as HttpWebRequest;
client.Proxy = new WebProxy("127.0.0.1", 8088);
var resp = client.GetResponse();
var html = new StreamReader(resp.GetResponseStream()).ReadToEnd();

Console.WriteLine("Read: {0}   Write: {1}", WebConnectionStats.Read, 
                                            WebConnectionStats.Written);

PS1: Ce nombre n'inclut pas les En-Têtes Tcp' longueur

PS2: Vous pouvez obtenir plus d'informations sur Fiddler core ici

6
répondu EZI 2014-09-16 05:43:57

une API Windows peut vous donner cette information:GetPerTcpConnectionEStats pour les connexions IPV4 et la fonction associée IPV6 GetPerTcp6ConnectionEStats. Remarque vous devez utiliser SetPerTcpConnectionEStats avant de pouvoir obtenir n'importe quelle statistique, et cela nécessite habituellement des droits d'administrateur...

Pour obtenir la liste de toutes les connexions, vous pouvez utiliser le GetExtendedTcpTable fonction. Il peut aussi vous donner l'id de processus de la connexion qui est très utile.

ce sont des API natives pas si faciles à utiliser, mais j'ai créé une classe TcpConnection qui enveloppe tout cela. Il est disponible ici dans une petite application WPF appelée IPStats:https://github.com/smourier/IPStats

donc, la difficulté ici est de lier votre .net HttpWebRequest à une connexion TCP à partir de la liste des connexions. Vous ne pouvez pas obtenir de stat avant que la connexion existe, mais une fois que vous avez créé la connexion, vous pouvez obtenir le stat correspondant avec un code comme ceci:

    static IEnumerable<TcpConnection> GetProcessConnection(IPEndPoint ep)
    {
        var p = Process.GetCurrentProcess();
        return TcpConnection.GetAll().Where(c => ep.Equals(c.RemoteEndPoint) && c.ProcessId == p.Id);
    }

    HttpWebRequest req = ...

    // this is how you can get the enpoint, or you can also built it by yourself manually
    IPEndPoint remoteEndPoint;
    req.ServicePoint.BindIPEndPointDelegate += (sp, rp, rc) =>
        {
            remoteEndPoint = rp;
            return null;
        };
    // TODO: here, you need to connect, so the connection exists
    var cnx = GetProcessConnection(remoteEndPoint).FirstOrDefault();

    // access denied here means you don't have sufficient rights
    cnx.DataStatsEnabled = true;

    // TODO: here, you need to do another request, so the values are incremented
    // now, you should get non-zero values here
    // note TcpConnection also has int/out bandwidth usage, and in/out packet usage.
    Console.WriteLine("DataBytesIn:" + cnx.DataBytesIn);
    Console.WriteLine("DataBytesOut:" + cnx.DataBytesOut);

    // if you need all connections in the current process, just do this
    ulong totalBytesIn = 0;
    ulong totalBytesOut = 0;
    Process p = Process.GetCurrentProcess();
    foreach (var cnx in TcpConnection.GetAll().Where(c => c.ProcessId == p.Id))
    {
        totalBytesIn += cnx.DataBytesIn;
        totalBytesOut += cnx.DataBytesOut;
    }

Il y a 3 inconvénients:

  • vous avez besoin d'être admin pour permettre de données statistiques;
  • vous ne pouvez pas obtenir les statistiques pour la toute première demande. Cela peut ne pas être un problème selon votre contexte;
  • la correspondance entre la connexion HttpWebRequest et la connexion TCP peut être plus délicate à déterminer car vous pouvez avoir plus d'une connexion à un terminal distant, même dans le même processus. La seule façon de distinguer est de déterminer le point final local (en particulier le port) et d'étendre la connexion Getprocess avec ce point final local. Malheureusement, il n'y a pas de moyen facile de le faire. Voici une réponse à ce sujet: Comment obtenir le numéro de port local D'un HttpWebRequest?

mise à jour: si vous voulez surveiller en permanence toutes les connexions pour un processus donné, j'ai écrit une classe utilitaire ProcessTcpConnections qui se souvient de toutes les connexions et additionne leurs utilisation. Il serait utilisée comme ceci (dans une console en application de l'échantillon):

class Program
{
    static void Main(string[] args)
    {
        ProcessTcpConnections p = new ProcessTcpConnections(Process.GetCurrentProcess().Id);
        Timer timer = new Timer(UpdateStats, p, 0, 100);

        do
        {
            // let's activate the network so we measure something...
            using (WebClient client = new WebClient())
            {
                client.DownloadString("http://www.example.com");
            }
            Console.ReadKey(true); // press any key to download again
        }
        while (true);
    }

    private static void UpdateStats(object state)
    {
        ProcessTcpConnections p = (ProcessTcpConnections)state;
        p.Update();
        Console.WriteLine("DataBytesIn:" + p.DataBytesIn + " DataBytesOut:" + p.DataBytesOut);
    }
}

public class ProcessTcpConnections : TcpConnectionGroup
{
    public ProcessTcpConnections(int processId)
        : base(c => c.ProcessId == processId)
    {
        ProcessId = processId;
    }

    public int ProcessId { get; private set; }
}

public class TcpConnectionGroup
{
    private List<TcpConnectionStats> _states = new List<TcpConnectionStats>();
    private Func<TcpConnection, bool> _groupFunc;

    public TcpConnectionGroup(Func<TcpConnection, bool> groupFunc)
    {
        if (groupFunc == null)
            throw new ArgumentNullException("groupFunc");

        _groupFunc = groupFunc;
    }

    public void Update()
    {
        foreach (var conn in TcpConnection.GetAll().Where(_groupFunc))
        {
            if (!conn.DataStatsEnabled)
            {
                conn.DataStatsEnabled = true;
            }

            TcpConnectionStats existing = _states.Find(s => s.Equals(conn));
            if (existing == null)
            {
                existing = new TcpConnectionStats();
                _states.Add(existing);
            }
            existing.DataBytesIn = conn.DataBytesIn;
            existing.DataBytesOut = conn.DataBytesOut;
            existing.LocalEndPoint = conn.LocalEndPoint;
            existing.RemoteEndPoint = conn.RemoteEndPoint;
            existing.State = conn.State;
            existing.LastUpdateTime = DateTime.Now;
        }
    }

    public ulong DataBytesIn
    {
        get
        {
            ulong count = 0; foreach (var state in _states) count += state.DataBytesIn; return count;
        }
    }

    public ulong DataBytesOut
    {
        get
        {
            ulong count = 0; foreach (var state in _states) count += state.DataBytesOut; return count;
        }
    }

    private class TcpConnectionStats
    {
        public ulong DataBytesIn { get; set; }
        public ulong DataBytesOut { get; set; }
        public IPEndPoint LocalEndPoint { get; set; }
        public IPEndPoint RemoteEndPoint { get; set; }
        public TcpState State { get; set; }
        public DateTime LastUpdateTime { get;  set; }

        public bool Equals(TcpConnection connection)
        {
            return LocalEndPoint.Equals(connection.LocalEndPoint) && RemoteEndPoint.Equals(connection.RemoteEndPoint);
        }
    }
}
6
répondu Simon Mourier 2017-05-23 12:26:06

Il est difficile de savoir exactement combien de trafic réseau se produit en raison d'un trafic Ethernet imprévisible et ce genre de chose, mais essentiellement l'essentiel de toute requête HTTP est:

method request-uri version
* (header : value)
CRLF
body

compte tenu de cela, vous pouvez calculer la longueur de la chaîne de requête:

HttpWebRequest req = ...;
StringBuilder requestText = new StringBuilder();

requestText.AppendFormat("{0} {1} HTTP/{2}.{3}", req.Method, req.RequestUri, req.ProtocolVersion.Major, req.ProtocolVersion.Minor);

requestText.AppendLine();

foreach (var header in req.Headers)
{
    requestText.AppendFormat("{0}: {1}", v, webReq.Headers[v]);
    requestText.AppendLine();
}

requestText.AppendLine();

// somehow add on the contents of the request stream, or just add that length later. I won't put that in this code because of stream positioning and all that

return System.Text.Encoding.UTF8.GetByteCount(requestText.ToString());

alors c'est assez similaire du côté de la réponse. Le format D'une réponse HTTP est:

version status-code status-description
* (header : value)
CRLF
body

Donc,

HttpWebResponse resp = ...;
StringBuilder responseText = new StringBuilder();

responseText .AppendFormat("HTTP/{0}.{1} {2} {3}", resp.ProtocolVersion.Major, resp.ProtocolVersion.Minor, (int)resp.StatusCode, resp.StatusDescription);
responseText .AppendLine();

foreach (var header in resp.Headers)
{
    responseText .AppendFormat("{0}: {1}", v, resp.Headers[v]);
    responseText .AppendLine();
}

responseText.AppendLine();

Ici, il y a un peu d'une prise de décision. Vous devez obtenir la longueur du corps de réponse. Il pourrait y avoir plus d'options, mais ce que je pense maintenant que vous pouvez:

  1. Ecrire un Stream wrapper qui saisit le nombre d'octets copiés. De cette façon, vous n'avez pas à vous soucier des transferts fractionnés, et il pourrait être un peu amusant d'écrire.
  2. content-length en-tête, bien qu'alors vous n'aurez pas si il y a n'est pas cet en-tête, comme c'est le cas pour transfer-encoding: chunked.
  3. lire le flux en utilisant la méthode que vous voulez, puis Ajouter la longueur de celui-ci dans.
  4. copier le flux vers un MemoryStream, puis passer que comme les nouveaux flux de réponse, tout en saisissant la longueur sur le chemin.

Que tout est dit, vous avez le extra frustration de s'inquiéter de la compression de contenu. Je vois que vous utiliser dans le vôtre, en fait. Étant donné la simplicité, je vais assumer GZip et aller avec la quatrième option. Vous pourriez vouloir pour étendre sur ce que j'écris ici, pour le rendre un peu plus complète.

// webReq.AutomaticDecompression = DecompressionMethods.None; is required for this, since we're handling that decompression ourselves.

using (var respStream = resp.GetResponseStream())
using (var memStream = new MemoryStream())
{
    respStream.CopyTo(memStream);

    using (var gzip = new System.IO.Compression.GZipStream(respStream, System.IO.Compression.CompressionMode.Decompress))
    using (var reader = new StreamReader(gzip))
    {
        var content = reader.ReadToEnd();

        // you may or may not actually care about this, depending on whether this is just light testing or if you'll actually have these metrics in production
    }

    return System.Text.Encoding.UTF8.GetByteCount(responseText.ToString()) + memStream.Length;
}

Maintenant, quelques mises en garde que je vois quand je regarde maintenant. D'autres pourraient en remarquer plus, et je les ajouterai si les gens commentent.

  • comme je l'ai déjà mentionné au début de ce numéro, il peut y avoir plus de trafic réseau à partir d'une seule requête que cela ne vous le dira.
  • Selon le client et le serveur, vous pourriez trouver que les véritables têtes pourraient être répertoriés avec un nombre différent de espace. Je ne crois pas que ce soit au-delà des spécifications HTTP, et même si c'est le cas, les gens le feront. Il y a donc une chance, par exemple, que vous voyiez un serveur content-type: text/html et un autre set content-type : text/html. Il y a au moins (Eh bien, exactement, puisque nous utilisons UTF-8) une différence d'un octet. Encore une fois, petit, mais c'est une divergence possible.

ce n'est qu'une estimation. C'est une bonne idée, mais c'est juste une estimation.

si vous cherchez une précision supplémentaire au prix d'une certaine simplicité, vous pouvez également écrire vous-même un proxy. L'idée D'un mandataire HTTP est qu'il obtient simplement la requête textuelle, donc c'est "super facile" d'obtenir ensuite la longueur. Le plus gros problème, bien sûr, est que vous devez alors écrire un proxy pleinement fonctionnel qui, selon toute probabilité, analyse et requière vos requêtes entrantes, et analyse et relaie toutes leurs réponses respectives. Certainement faisable, mais ce n'est pas insignifiant. Surtout si vous avez à vous soucier de SSL.

au niveau le plus élémentaire, bien sûr, vous pourriez écrire, essentiellement, une alternative à un programme comme WireShark. Je ne sais pas comment faire, et je ne dirais pas vous déranger, à moins que vous vraiment besoin d'elle. Ça ne te donnerait pas une idée parfaite non plus. Juste plus près.

et maintenant, tout est dit, et bon sang, c'était un peu dit, si vous faites ça pour le profilage, Il y a de fortes chances que les outils construits dans Visual Studio vous permettra de le faire. Certes, je suis loin de les connaître--Je ne les ai jamais ouverts--mais je crois qu'il y a des profileurs de trafic réseau disponibles. Bien sûr, je doute qu'ils travaillent sur toutes les plateformes comme celle-ci. Mais ce serait certainement une approche plus facile.

aussi, si quelqu'un remarque des fautes de frappe ici, j'ai copié-collé quelques fois et je pense que je les ai toutes, mais n'hésitez pas à me les faire savoir ou à les corriger.

4
répondu Matthew Haugen 2014-08-20 02:13:50

il peu moche, mais vous pouvez utiliser de traçage réseau, puis analyse le journal. voir http://msdn.microsoft.com/en-us/library/ty48b824(v=vs. 110).aspx pour activer le traçage réseau

j'ai ajouter le code de base ( je sais que j'ai un bug dans l'analyse du journal, mais l'idée devrait être clair )

NetworkListner.cs

using System;
using System.Diagnostics;
using System.Globalization;
using System.Text.RegularExpressions;

namespace NetworkTracing
{
    /// <summary>
    /// Description of NetworkListner.
    /// </summary>
    public class NetworkListner : TraceListener
    {
        public static int BytesSent { get; private set;} 
        public static int BytesReceived { get; private set;}
        private bool _inSend = false;
        private bool _inReceived = false;
        private string _lastMessage = "";
        private Regex _lengthRegex = new Regex(@"(\[\d*\]) ([\dA-F]*)");
        public NetworkListner()
        {
            BytesSent = 0;
            BytesReceived = 0;          
        }

        private int ExtractNumOfBytes(string message){
            string lengthUntilThisLineStr = null;
            try {           
                var match = _lengthRegex.Match(message);                
                lengthUntilThisLineStr = match.Groups[2].Value;
            } catch (ArgumentException ex) {
                // Syntax error in the regular expression
            }
            if (String.IsNullOrEmpty(lengthUntilThisLineStr)) {
                return 0;
            }
            var lengthUntilThisLine = int.Parse(lengthUntilThisLineStr,NumberStyles.HexNumber);
            return lengthUntilThisLine;
        }

        public override void Write(string message) {
            if (message.Equals("System.Net.Sockets Verbose: 0 : ")) {
                return;
            }
            if (message.Contains("Exiting Socket#")) {
                int bytes = ExtractNumOfBytes(_lastMessage);
                if (_inSend) {
                    _inSend = false;
                    BytesSent += bytes;
                }else if (_inReceived) {
                    _inReceived = false;
                    BytesReceived += bytes;
                }   
            }           
            else if (message.Contains("Data from Socket")){
                if (message.Contains("Send")) {
                    _inSend = true;
                }
                else if (message.Contains("Receive")) {
                    _inReceived = true;
                }
            }
            _lastMessage = message;
        }

        public override void WriteLine(string message) {
            Write(message + Environment.NewLine);
        }
    }
}

Programme.cs

using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net;

namespace NetworkTracing
{
    class Program
    {
        public static void Main(string[] args)
        {           
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
            request.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0";
            using (WebResponse response = request.GetResponse())
            {
                using (Stream strumien = response.GetResponseStream())
                {
                    using (StreamReader sr = new StreamReader(strumien))
                    {
                        var res = sr.ReadToEnd();
                        Console.WriteLine("Send -> {0}",NetworkListner.BytesSent);
                        Console.WriteLine("Recieve -> {0}",NetworkListner.BytesReceived);
                        Console.ReadLine();
                    }
                }
            }
        }
    }

App.config

<configuration>
<system.diagnostics>
    <sources>
      <source name="System.Net.Sockets" tracemode="includehex" maxdatasize="1024">
        <listeners>
          <add name="network"/>
        </listeners>
      </source>
    </sources>
     <switches>
      <add name="System.Net.Sockets" value="Verbose"/>      
    </switches>
    <sharedListeners>
      <add name="network"
        type="NetworkTracing.NetworkListner, NetworkTracing"
      />
    </sharedListeners>
    <trace autoflush="true"/>
  </system.diagnostics>
</configuration>

vous aussi besoin de compiler votre projet avec trace flag (ce flag est par défaut dans debug ) par:

  1. sélectionnez un projet dans l'Explorateur de solutions, dans le menu Projet
  2. cliquez sur Propriétés.
  3. Cliquez sur l'onglet Compiler.
  4. cliquez sur le bouton Avancé Compiler Options pour ouvrir le Avancé Compilateur boîte de dialogue Paramètres.
  5. sélectionnez la case à cocher définir de la constante de TRACE, puis cliquez sur OK.
3
répondu Noam Wies 2014-09-10 06:33:16

si votre application client communique avec votre(Vos) serveur (s) IIS connu (s), alors j'essaierai d'obtenir ces données à partir des journaux IIS. Vérifiez les octets cs (octets de requête aka du client au serveur) et sc (octets de réponse aka du serveur au client). http://technet.microsoft.com/en-us/library/cc754702 (v = ws.10).aspx

1
répondu BateTech 2014-08-25 11:03:42

je pense que vous pouvez utiliser .NET CLR Réseau compteur de performance comme il peut vous donner des octets envoyés et reçus par domaine d'application

http://msdn.microsoft.com/en-us/library/70xadeyt%28v=vs.110%29.aspx

j'ai écrit une classe Helper pour vérifier l'exactitude et les résultats sont similaires à Windows ResourceMonitor, donc je crois que l'exactitude devrait être acceptable.

comment utiliser:

voici le Helper classe:

using System.Diagnostics;
using System.Linq;

public class NetworkMonitor
{
    private PerformanceCounter _bytesSent;
    private PerformanceCounter _bytesReceived;
    private readonly int _processId;
    private bool _initialized;

    public NetworkMonitor(int processID)
    {
        _processId = processID;
        Initialize();
    }

    public NetworkMonitor()
        : this(Process.GetCurrentProcess().Id)
    {

    }
    private void Initialize()
    {
        if (_initialized)
            return;

        var category = new PerformanceCounterCategory(".NET CLR Networking 4.0.0.0");
        var instanceNames = category.GetInstanceNames().Where(i => i.Contains(string.Format("p{0}", _processId)));
        if (!instanceNames.Any()) return;

        _bytesSent = new PerformanceCounter
        {
            CategoryName = ".NET CLR Networking 4.0.0.0",
            CounterName = "Bytes Sent",
            InstanceName = instanceNames.First(),
            ReadOnly = true
        };

        _bytesReceived = new PerformanceCounter
        {
            CategoryName = ".NET CLR Networking 4.0.0.0",
            CounterName = "Bytes Received",
            InstanceName = instanceNames.First(),
            ReadOnly = true
        };

        _initialized = true;
    }

    public float GetSentBytes()
    {
        Initialize(); //in Net4.0 performance counter will get activated after first request
        return _initialized ? _bytesSent.RawValue : 0;
    }
    enter code here
    public float GetReceivedBytes()
    {
        Initialize(); //in Net4.0 performance counter will get activated after first request
        return _initialized ? _bytesReceived.RawValue : 0;
    }
} 

vous devriez ajouter cette partie à votre application.config

  <system.net>
    <settings>
      <performanceCounters enabled="true" />
    </settings>
  </system.net>

et voici l'échantillon que j'ai utilisé pour vérifier l'exactitude de la base sur votre propre méthode:

   private static void Main(string[] args)
        {
            var netMonitor = new NetworkMonitor();

            var received = netMonitor.GetReceivedBytes();
            var sent = netMonitor.GetSentBytes();

            Console.WriteLine("received:{0}, sent:{1}", received, sent);
            func_fetch_Page("http://www.google.com");

            received = netMonitor.GetReceivedBytes();
            sent = netMonitor.GetSentBytes();

            Console.WriteLine("received:{0}, sent:{1}", received, sent);
            Console.ReadKey();
        }
1
répondu user3473830 2014-09-17 05:33:22