Laden...

WebClient mitloggen wieviel Bytes tatsächlich runtergeladen wurden

Erstellt von nicky vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.317 Views
N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren
WebClient mitloggen wieviel Bytes tatsächlich runtergeladen wurden

Hi, ich verwende WebClient für den Download einer Xml Datei. Mein Request akzeptiert Kompression und der Webserver liefert diese auch. Jetzt möchte ich mitschreiben wie viel bytes ich tatsächlich runterlade. Mit dem WebClient komm ich bisher nur an die "uncompressed bytes". Hat jemand eine Idee wie ich herausfinde, wie viel "compressed bytes" ich runterlade?

using System;
using System.Net;

namespace Test_Downloader
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new CustomWebClient())
            {
                client.DownloadProgressChanged += Client_DownloadProgressChanged;
                var url = "http://www.example.com/foo.xml";
                client.DownloadFileAsync(new Uri(url), "bar.txt");
            }
            Console.ReadLine();
        }

        private static void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            //Console.WriteLine("downloaded bytes: {0}", (int)e.BytesReceived);
            Console.WriteLine("downloaded total bytes: {0}", (int)e.TotalBytesToReceive);
        }
    }

    class CustomWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
            return request;
        }
    }
}

16.807 Beiträge seit 2008
vor 6 Jahren

Der WebClient ist ein Wrapper für die WebRequest Klasse.
Sie ist komfortabler, simpler aber versteckt eben auch vieles. Reicht Dir das nicht aus, dann verwende den WebRequest direkt.

N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren

Danke für deinen Input, aber wie ich an die tatsächlichen Bytes komme ist mir immernoch ein Rätsel. Hier war mein Versuch aber so erhalte ich auch nur wieder den dekomprimierten Wert.

    class HTTPDownload
    {
        public static long Download(string url, string destination)
        {
            HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
            httpRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
            httpRequest.Method = WebRequestMethods.Http.Get;

            HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            Stream httpResponseStream = httpResponse.GetResponseStream();

            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int bytesRead = 0;

            long length = 0;
            FileStream fileStream = File.Create(destination);
            while ((bytesRead = httpResponseStream.Read(buffer, 0, bufferSize)) != 0)
            {
                length += bytesRead;
                fileStream.Write(buffer, 0, bytesRead);
            }

            return length;
        }
    }
849 Beiträge seit 2006
vor 6 Jahren

Ohne es probiert zu haben, oder zu wissen ob es geht..:

Hast Du probiert die AutomaticDecrompression zu deaktivieren, die empfangenen Bytes zu zählen und dann zu dekomprimieren (DeflateStream)?

An die tatsächlichen Bytes wirst Du so aber auch nicht kommen, da immer ein wenig overhead da ist (header etc.)

N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren

Das hört sich vielversprechend an, ich schau es mir mal an! 😃

D
152 Beiträge seit 2013
vor 6 Jahren

Wofür braucht Du die Anzahl der tatsächlichen übertragenen Byte?
Im allgemeinen sendet der Server die Anzahl im Header Content-Length mit.
Steht der gewünschte Werte nicht auch in der Eigenschaft HttpWebResponse.ContentLength?

N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren

Ich möchte den Traffic mitschreiben. Content-Length liefert -1 wenn man die Kompression verwendet. Ich glaube das liegt daran, dass es in Chunks übermittelt wird.

16.807 Beiträge seit 2008
vor 6 Jahren

Mir ist immer noch nicht ganz klar, was Du messen willst.
Sind es nur die Bytes, die über den WebClient laufen, oder die RAW-Bytes die über das Kabel gehen (inkl. Header und Handshake...) oder willst Du nur wissen, welche Dateigröße am Schluss raus kommt?

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

führt dazu, dass der WebRequest automatisch die Decrompression vernimmt, Du hier also nicht an die Rohdaten der Übertragung ran kommst.

N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren

Ich möchte wissen wie viele Bytes tatsächlich übertragen werden um zu überwachen, wie viel Traffic mein Tool verursacht.

Hintergrund ist, dass das Tool auf PCs mit Trafficbeschränkung läuft.

N
nicky Themenstarter:in
232 Beiträge seit 2011
vor 6 Jahren

Der Tipp die Kompression manuell durchzuführen war glaub ich ganz gut, hier meine aktuelle Lösung:

using System;
using System.IO;
using System.IO.Compression;
using System.Net;

namespace TestCompressionDownload
{
    class Program
    {
        static void Main(string[] args)
        {
            var url = "http://www.example.com/program.xml";

            GZipWebClient webClient = new GZipWebClient();
            var compressed = webClient.DownloadData(url);
            var uncompressed = Decompress(compressed);

            ByteArrayToFile("foo.xml", uncompressed);

            Console.WriteLine("File compressed: {0}", BytesToMegabytesAsText(compressed.Length));
            Console.WriteLine("File uncompressed: {0}", BytesToMegabytesAsText(uncompressed.Length));
            Console.ReadLine();
        }

        static byte[] Decompress(byte[] gzip)
        {
            using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
            {
                const int size = 4096;
                byte[] buffer = new byte[size];
                using (MemoryStream memory = new MemoryStream())
                {
                    int count = 0;
                    do
                    {
                        count = stream.Read(buffer, 0, size);
                        if (count > 0)
                        {
                            memory.Write(buffer, 0, count);
                        }
                    }
                    while (count > 0);
                    return memory.ToArray();
                }
            }
        }

        static bool ByteArrayToFile(string filename, byte[] byteArray)
        {
            using (var fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
            {
                fs.Write(byteArray, 0, byteArray.Length);
                return true;
            }
        }

        static string BytesToMegabytesAsText(long length)
        {
            var mb = (length / 1024f) / 1024f;
            return String.Format("{0} MB", mb);
        }
    }

    public class GZipWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest httpRequest = base.GetWebRequest(address) as HttpWebRequest;
            httpRequest.AutomaticDecompression = DecompressionMethods.None;
            httpRequest.Headers.Add("Accept-Encoding", "gzip,deflate");
            return httpRequest;
        }
    }
}

// Edit: Es ist natürlich sinnvoll nicht jede Datei zu dekomprimieren. Eine Abfrage könnte so aussehen:

                GZipWebClient webClient = new GZipWebClient();
                var data = webClient.DownloadData(link);
                var bytesDownloaded = data.Length;
                if (webClient.ResponseHeaders["Content-Encoding"] == "gzip")
                {
                    data = DecompressGzip(data);
                }
                ByteArrayToFile(filename, data);