C# 如何计算HttpWebRequest花费的出站和入站internet流量

C# 如何计算HttpWebRequest花费的出站和入站internet流量,c#,wpf,httpwebrequest,webrequest,network-traffic,C#,Wpf,Httpwebrequest,Webrequest,Network Traffic,我有下面的函数来获取页面。我的问题是我想计算一下上网的费用 入站(下载)和出站流量(已发送) 我该怎么做?多谢各位 我的职能 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", str

我有下面的函数来获取页面。我的问题是我想计算一下上网的费用

入站(下载)和出站流量(已发送)

我该怎么做?多谢各位

我的职能

 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应用程序

@Simon Mourier我如何计算花费的流量

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));
        }
    }
}
由于某些不可预测的以太网通信量等原因,很难确切知道发生了多少网络通信量,但本质上任何HTTP请求的要点都是:

method request-uri version
* (header : value)
CRLF
body
因此,您可以计算出请求字符串的长度:

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());
那么,对于响应端来说,情况就非常相似了。HTTP响应的格式为:

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

在这里,有一点决定要做。您需要获得响应主体的长度。可能有更多的选择,但我现在想的是你可以:

  • 编写一个
    包装器,获取复制的字节数。这样,您就不必担心分块传输,编写代码也会很有趣
  • 使用
    content-length
    标题,尽管如果没有该标题,您将无法获得它,就像
    传输编码:chunked
    一样
  • 使用您想要的任何方法读取流,然后在中添加该流的长度
  • 将流复制到
    内存流
    ,然后将其作为新响应流传递,同时在途中获取长度
  • 综上所述,您在担心内容压缩时会有额外的挫败感。事实上,我看到你在自己的作品中使用了它。考虑到简单性,我将假设GZip并使用第四个选项。你可能想对我在这里写的内容进行扩展,使之更全面一点

    // 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;
    }
    
    现在,我看到了一些注意事项。其他人可能会注意到更多,如果有人发表评论,我会将他们添加进来

    • 正如我在本文开头提到的,一个请求的网络流量可能比它告诉您的要多
    • 根据客户机和服务器的不同,您可能会发现实际的头可以用不同数量的空格列出。我不认为这超出了HTTP规范,即使是这样,人们也会这么做。因此,有可能,例如,您会看到一个服务器集
      内容类型:text/html
      和另一个集
      内容类型:text/html
      。因为我们使用UTF-8,所以至少有一个字节的差异。同样,很少,但这是一个可能的差异
    这只是一个估计。这是一个很好的估计,但只是一个估计

    如果您希望以简单为代价获得更高的准确性,您也可以为自己编写一个代理。HTTP代理的思想是它只获取逐字请求,因此获取长度“非常容易”。当然,最大的问题是,您必须编写一个功能齐全的代理,它很可能解析并重新请求传入的请求,解析并转发它们各自的响应。当然是可行的,但这不是小事。特别是当您不得不担心SSL时

    当然,在最基本的层面上,你可以编写一个替代WireShark的程序。我不知道怎么做,除非你真的需要,否则我不建议你麻烦。那也不会给你一个完美的主意。就在附近

    现在,所有这些都说了,男孩,这是相当多的说,如果你这样做的目的是分析,有一个很好的机会,内置到VisualStudio的工具将允许你这样做。诚然,我对它们的了解还远远不够——我甚至从未打开过它们——但我相信有可用的网络流量分析器。当然,我怀疑他们会在这样的平台上工作。但这肯定是一个更容易的方法


    此外,如果有人碰巧注意到这里有任何打字错误,我确实复制粘贴了几次,我想我都得到了,但请随时通知我或修复它们。

    如果您的客户端应用程序正在与已知的IIS服务器通信,那么我会尝试从IIS日志中获取这些数据。检查cs字节(客户端到服务器字节,又称请求字节)和sc字节(服务器到客户端字节,又称响应字节)

    一个Windows API可以为您提供以下信息:用于IPV4连接和相关IPV6 GetPertCP6ConnectionStats函数。请注意,您需要使用之前才能获得任何统计,这通常需要管理员权限

    要获取所有连接的列表,可以使用函数。它还可以为您提供非常有用的连接进程id

    这些都是本机API,不太容易使用,但我创建了一个TcpConnection类来封装所有这些。可在一个名为IPStats的小型WPF应用程序中获得:

    因此,这里的困难在于从连接列表中将.NET HttpWebRequest链接到TcpConnection。 在连接存在之前,您无法获取任何stat,但是一旦创建了连接,您就可以使用如下代码获取相应的stat:

        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;
        }
    
    静态IEnumerable GetProcessConnection(IPEndPoint ep)
    {
    var p=Process.GetCurrentProcess();
    返回TcpConnection.GetAll(),其中(c=>ep.Equals(c.RemoteEndPoint)和&c.ProcessId==p.Id);
    }
    HttpWebRequest请求=。。。
    //这是您获取enpoint的方式,或者您也可以自己手动构建它
    IPEndPoint远程端点;
    req.ServicePoint.BindIPEndPointDelegate+=(sp、rp、rc)=>
    {
    remoteEndPoint=rp;
    返回null;
    };
    //TODO:在这里,您需要连接,因此连接存在
    var cnx=GetProcessConnection(remoteEndPoint).FirstOrDefault();
    //此处拒绝访问表示您没有足够的权限
    cnx.DataStatsEnabled=true;
    //TODO:在这里,您需要执行另一个请求,因此值会递增
    //现在,你应该
    
        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;
        }
    
    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);
            }
        }
    }
    
    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);
            }
        }
    }
    
    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();
                        }
                    }
                }
            }
        }
    
    <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>
    
    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);
    
    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;
        }
    } 
    
      <system.net>
        <settings>
          <performanceCounters enabled="true" />
        </settings>
      </system.net>
    
       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();
            }