我有以下功能来获取页面。我的问题是我想计算花了多少互联网连接
入站(下载)和出站流量(已发送)
我该怎么做?谢谢
我的功能
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));
}
}
}
答案 0 :(得分:6)
一个Windows API可以为您提供以下信息:GetPerTcpConnectionEStats用于IPV4连接和相关的IPV6 GetPerTcp6ConnectionEStats功能。请注意,您需要先使用SetPerTcpConnectionEStats才能获得任何统计信息,这通常需要管理员权限...
要获取所有连接的列表,可以使用GetExtendedTcpTable功能。它还可以为您提供连接的进程ID,这非常有用。
这些本机API并不容易使用,但我创建了一个包装所有这些的TcpConnection类。它可以在一个名为IPStats的小型WPF应用程序中找到:https://github.com/smourier/IPStats
因此,这里的困难是将.NET HttpWebRequest链接到连接列表中的TcpConnection。 在连接存在之前,您无法获得任何统计信息,但是一旦创建了连接,就可以使用如下代码获取相应的连接:
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;
}
有3个缺点:
更新:如果你想连续监控给定进程的所有连接,我编写了一个ProcessTcpConnections实用程序类来记住所有连接并总结它们的用法。它会像这样使用(在控制台应用程序示例中):
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);
}
}
}
答案 1 :(得分:6)
您可以使用FiddlerCore创建代理(只需要一个dll来引用),并将 WebProxy 设置为HttpWebRequest来计算发送和接收的字节数
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:此计数不包括 Tcp标题长度
PS2 :您可以获得有关Fiddler核心的更多信息here
答案 2 :(得分:4)
由于一些不可预测的以太网流量等等,很难知道完全正在发生多少网络流量,但基本上任何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
所以,
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();
这里有一点决定。您需要获取响应正文的长度。可能有更多的选择,但我现在想的是你可以:
Stream
包装器,用于获取复制的字节数。这样你就不必担心分块转移了,写起来可能会很有趣。content-length
标题,但如果不该标题,则不会得到它,如transfer-encoding: chunked
的情况。MemoryStream
,然后将其作为新的响应流传递,同时抓住路上的长度。所有人都说,你对额外担心内容压缩感到沮丧。事实上,我看到你在你的身上使用它。鉴于简单性,我将假设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;
}
现在,我现在看到的一些警告。其他人可能会注意到更多,如果人们发表评论我会添加它们。
content-type: text/html
和另一个集content-type : text/html
。 至少(确实,因为我们使用的是UTF-8)一个字节的区别。再说一点,但这可能存在差异。这只是一个估计。这是一个很好的,但它只是一个估计。
如果您想以一些简单的方式寻找额外的准确性,您也可以自己编写代理。 HTTP代理的想法是它只是获得逐字的请求,因此获得长度“非常容易”。当然,最大的问题是你必须编写一个功能齐全的代理,它很可能解析和重新请求你的传入请求,并解析和转发他们各自的响应。当然可行,但这不是微不足道的。特别是如果您不得不担心SSL。
在最基本的层面上,当然,你可以写一个像WireShark这样的程序的替代品。我不知道该怎么做,除非你真的需要它,否则我不建议你这么做。这仍然不会给你一个完美的想法。更接近。
现在,所有人都说,而且男孩,这是相当多的说法,如果你为了剖析的目的这样做,那么Visual Studio中内置的工具很可能会让你这样做。不可否认,我对他们的了解很远 - 我从来没有打开它们 - 但我相信有网络流量分析器可用。当然,我怀疑他们会像这样在每个平台上工作。但这肯定是一种更容易的方法。
此外,如果有人碰巧在这里注意到任何拼写错误,我会复制粘贴几次,我想我已经完成了所有这些,但请随时告诉我或者修复它们。
答案 3 :(得分:3)
我添加了基本代码(我知道我在解析日志时遇到了错误但想法应该清楚了)
<强> 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);
}
}
}
<强> Program.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>
您还需要通过以下方式编译带有跟踪标志的项目(此标志在调试中是默认的):
答案 4 :(得分:1)
如果您的客户端应用程序正在与您的已知IIS服务器进行通信,那么我将尝试从IIS日志中获取此数据。检查cs-bytes(客户端到服务器字节,即请求字节)和sc-bytes(服务器到客户端字节,即响应)。 http://technet.microsoft.com/en-us/library/cc754702(v=ws.10).aspx
答案 5 :(得分:1)
我认为你可以使用 .NET CLR Networking 性能计数器,因为它可以为每个AppDomain提供发送和接收的字节
http://msdn.microsoft.com/en-us/library/70xadeyt%28v=vs.110%29.aspx
我写了一个Helper类来验证准确性,结果与Windows ResourceMonitor类似,所以我认为准确性应该是可以接受的。
使用方法:
这是Helper类:
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;
}
}
您应该将此部分添加到您的app.config
<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();
}