C# lädt nicht Daten vom FTP Server, listet sie aber auf

  • Sonstige

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von GamerXIOS.

    C# lädt nicht Daten vom FTP Server, listet sie aber auf

    Tag,

    ich wollte nun ein Launcher Schreiben, der mir ein ca. 1000 Dateien runterlädt, jedoch macht er das nicht.
    Er zeigt mir einige an, lädt aber keine Datei runter.

    Quellcode:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.IO;
    7. using System.Linq;
    8. using System.Net;
    9. using System.Text;
    10. using System.Threading.Tasks;
    11. using System.Windows.Forms;
    12. namespace WindowsFormsApplication1
    13. {
    14. public partial class Form1 : MetroFramework.Forms.MetroForm
    15. {
    16. string ftpUser = "";
    17. string ftpPW = "";
    18. public Form1()
    19. {
    20. InitializeComponent();
    21. }
    22. private void Form1_Load(object sender, EventArgs e)
    23. {
    24. }
    25. private void metroTile2_Click(object sender, EventArgs e)
    26. {
    27. if (!Directory.Exists(armaInstallDir.Text + "@ruhrpott-life"))
    28. {
    29. System.IO.Directory.CreateDirectory(armaInstallDir.Text + "@ruhrpott-life");
    30. }
    31. lblStatus.Text = "Hole Dateien von FTP";
    32. Application.DoEvents();
    33. List<FtpData> filesToDownload = GetFilesAndDirectoriesToDownload("ftp://../ruhrpott/ruhrpott-life", new DirectoryInfo(@armaInstallDir.Text + "@ruhrpott-life"), true);
    34. lblStatus.Text = "Hole Dateien von FTP fertig";
    35. Application.DoEvents();
    36. System.Threading.Thread.Sleep(1000);
    37. lblStatus.Text = "Starte Download von " + filesToDownload.Count.ToString() + " Dateien";
    38. pbDownloadProgress.Maximum = filesToDownload.Count;
    39. pbDownloadProgress.Value = 0;
    40. foreach (FtpData file in filesToDownload)
    41. {
    42. DownloadFileAsynchron(file);
    43. }
    44. }
    45. private class FtpData
    46. {
    47. public string RequestUriString;
    48. public string FileName;
    49. public DirectoryInfo Directory;
    50. public int DownloadAttemps;
    51. public FtpData(string requestUriString, string fileName, DirectoryInfo directory)
    52. {
    53. RequestUriString = requestUriString;
    54. FileName = fileName;
    55. Directory = directory;
    56. DownloadAttemps = 0;
    57. }
    58. }
    59. private List<FtpData> GetFilesAndDirectoriesToDownload(string requestUriString, DirectoryInfo workingDirectory, bool recursive)
    60. {
    61. List<FtpData> files = new List<FtpData>();
    62. List<FtpData> directories = new List<FtpData>();
    63. try
    64. {
    65. FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(requestUriString);
    66. req.Credentials = new NetworkCredential(ftpUser, ftpPW);
    67. req.Proxy = new WebProxy();
    68. req.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
    69. req.KeepAlive = false;
    70. using (FtpWebResponse response = (FtpWebResponse)req.GetResponse())
    71. {
    72. using (Stream dataStream = response.GetResponseStream())
    73. {
    74. using (StreamReader reader = new StreamReader(dataStream))
    75. {
    76. while (!reader.EndOfStream)
    77. {
    78. string entry = reader.ReadLine();
    79. if (entry.StartsWith("d"))
    80. {
    81. string directoryName = GetEntryName(entry);
    82. if (directoryName != "." && directoryName != ".." && recursive)
    83. {
    84. DirectoryInfo subDir = Directory.CreateDirectory(workingDirectory.FullName + "\\" + directoryName);
    85. directories.Add(new FtpData(requestUriString + "/" + directoryName, "", subDir));
    86. }
    87. }
    88. else
    89. {
    90. files.Add(new FtpData(requestUriString + "/" + GetEntryName(entry), GetEntryName(entry), workingDirectory));
    91. }
    92. }
    93. }
    94. }
    95. }
    96. foreach (FtpData dir in directories)
    97. {
    98. files.AddRange(GetFilesAndDirectoriesToDownload(dir.RequestUriString, dir.Directory, true));
    99. }
    100. }
    101. catch (Exception ex)
    102. {
    103. MessageBox.Show(ex.ToString());
    104. }
    105. return files;
    106. }
    107. private string GetEntryName(string entry)
    108. {
    109. string result = entry.Substring(entry.LastIndexOf(":"));
    110. result = result.Substring(result.IndexOf(" ") + 1);
    111. return result;
    112. }
    113. private void DownloadFileAsynchron(FtpData file)
    114. {
    115. using (WebClient wc = new WebClient())
    116. {
    117. wc.Proxy = new WebProxy();
    118. wc.DownloadDataCompleted += new DownloadDataCompletedEventHandler(wc_DownloadDataCompleted);
    119. file.DownloadAttemps += 1;
    120. wc.DownloadDataAsync(new Uri(file.RequestUriString), file);
    121. AllFIleList.Items.Add(new Uri(file.RequestUriString));
    122. }
    123. }
    124. void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
    125. {
    126. FtpData file = (FtpData)e.UserState;
    127. if (e.Error == null)
    128. {
    129. try
    130. {
    131. File.WriteAllBytes(file.Directory.FullName + @"\" + file.FileName, e.Result);
    132. pbDownloadProgress.Value += 1;
    133. }
    134. catch (Exception ex)
    135. {
    136. MessageBox.Show(ex.ToString());
    137. }
    138. }
    139. else
    140. {
    141. if (file.DownloadAttemps <= 3)
    142. DownloadFileAsynchron(file);
    143. else
    144. Console.Write("File " + file.FileName + " konnte nicht heruntergeladen werden.\n");
    145. }
    146. }
    147. }
    148. }

    GamerXIOS schrieb:

    ich wollte nun ein Launcher Schreiben, der mir ein ca. 1000 Dateien runterlädt, jedoch macht er das nicht.
    Er zeigt mir einige an, lädt aber keine Datei runter.
    Trenne die Probleme, und löse sie nacheinander.
    Als erstes: solange du die zu downloadenden Daten nicht vollständig ermitteln kannst, brauchst du dir ums Gedownloade keinen Kopp zu machen.
    Das hier:

    GamerXIOS schrieb:

    C#-Quellcode

    1. string ftpUser = "";
    2. string ftpPW = "";

    ist grob fahrlässig. Jeder kann die Daten aus dem Programm auslesen und so auf deinen Server zugreifen.
    Allein FTP ist schon grob fahrlässig. Das Protokoll ist überhaupt nicht dafür geeignet. Dafür gibt es HTTP(S). Sonst kann ich Dir ganz einfach die Credentials abgreifen und dann war es das. Abgesehen davon, dass sie schon im Code stehen. ;)
    Außerdem lädst Du somit wohl einfach Binaries runter und führst sie danach aus bzw. sie werden dann irgendwo vom Spiel benutzt und sind bestenfalls nur fehlerhaft. Das kannst Du keinem Benutzer und vor allem Dir nicht zumuten.

    Da gehört ein vernünftiges Validierungsverfahren dahinter, sonst kann ja jeder die Dateien einfach manipulieren. Kein Programm würde das so handhaben.

    Sicherheit: Gefahrenquelle Quellcode
    Updater - Warum sollte man eigene Updater vermeiden?
    Sicherheitsrisiken bei der Verwendung von Ftp und Datenbanken

    Und wenn Du das alles angepasst und geändert hast, dann kannst Du auch anders ansetzen, weil es über HTTP(S) dann kein Problem mehr ist, was in .NET herunterzuladen.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Gib' das mit FTP auf!
    C# lädt nicht Daten vom FTP Server, listet sie aber auf

    Nochmal: Es ist unsicher wie sau und es geht auch viel einfacher und schöner mit HTTP(S). ;)

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Hast Du denn einen Webspace? Dann hast Du automatisch Zugriff via HTTP. HTTPS nur mit SSL-Zertifikat, damit die Verbindung verschlüsselt ist, was aber bei korrektem Signaturverfahren (RSA 4096 Bit + SHA512) zur Prüfung/Validierung der Daten nicht zwingend erforderlich ist. hauptsache Du prüfst die Daten, damit der Benutzer im Launcher alles sicher runterladen kann.

    Wenn ja:

    msdn.microsoft.com/de-de/libra….webclient(v=vs.110).aspx
    msdn.microsoft.com/de-de/libra…ceprovider(v=vs.110).aspx
    de.wikipedia.org/wiki/Asymmetrisches_Kryptosystem

    Wenn nein:

    Schaff Dir einen Webspace an, FTPS für privaten Zweck dazu ist ok, ist auch standardmäßig dabei, aber hauptsache HTTP(S). FTP aber nie benutzen und schon gar nicht im Code oder in Programmen (auch nicht FTPS), falls es darum geht, von Deinem eigenen Server/whatever was zu laden. Dann kannste das mit dem WebClient regeln.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ich habe einen Webspace, jedoch wie Liste ich nun alle Dateien auf ? Habe nun etwas damit ich eine Datei laden kann, aber stehe auf dem Schlauch wie das mit HTTP Funktioniert.

    Spoiler anzeigen

    C#-Quellcode

    1. string DLSite = "..../addons/Jonzie_Carpack.pbo";
    2. string saveDIR = @"...\addons\Jonzie_Carpack.pbo";
    3. private void Form1_Load(object sender, EventArgs e)
    4. {
    5. }
    6. private void metroTile2_Click(object sender, EventArgs e)
    7. {
    8. if (!Directory.Exists(armaInstallDir.Text + "@ruhrpott-life"))
    9. {
    10. System.IO.Directory.CreateDirectory(armaInstallDir.Text + "@ruhrpott-life");
    11. }
    12. lblStatus.Text = "Hole Dateien vom Server";
    13. WebClient client = new WebClient();
    14. client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    15. client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    16. // Starts the download
    17. client.DownloadFileAsync(new Uri(DLSite), saveDIR);
    18. Console.Write(DLSite + "\n");
    19. Console.Write(saveDIR );
    20. }
    21. void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    22. {
    23. double bytesIn = double.Parse(e.BytesReceived.ToString());
    24. double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
    25. double percentage = bytesIn / totalBytes * 100;
    26. DownloadProgress.Value = int.Parse(Math.Truncate(percentage).ToString());
    27. }
    28. void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    29. {
    30. MessageBox.Show("Download Completed");
    31. }


    stackoverflow.com/questions/12…-to-get-directory-listing
    Hier sollten ein paar Ansätze sein. Sieht aber schon mal besser aus. Und ohne Credentials, toll, nicht? ;)

    Wenn Du das dann hast, dann schau Dir mal das mit dem asymm. Kryptosystem an. Musst dann auf beiden Seiten natürlich anpassen, aber ist ganz wichtig.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Habs nun so, nun lädt er nur eine Datei runter, die er eigentlich nicht sollte (Parent Directory) und macht dann nicht weiter.

    C#-Quellcode

    1. private void metroTile2_Click(object sender, EventArgs e)
    2. {
    3. if (!Directory.Exists(armaInstallDir.Text + "@ruhrpott-life"))
    4. {
    5. System.IO.Directory.CreateDirectory(armaInstallDir.Text + "@ruhrpott-life");
    6. }
    7. lblStatus.Text = "Hole Dateien vom Server";
    8. WebClient client = new WebClient();
    9. string url = "http://..../ruhrpott/ruhrpott-life/";
    10. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    11. using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    12. {
    13. using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    14. {
    15. string html = reader.ReadToEnd();
    16. Regex regex = new Regex(GetDirectoryListingRegexForUrl(url));
    17. MatchCollection matches = regex.Matches(html);
    18. if (matches.Count > 0)
    19. {
    20. foreach (Match match in matches)
    21. {
    22. if (match.Success)
    23. {
    24. if (isDownload == false)
    25. {
    26. Console.WriteLine(match.Groups["name"]);
    27. client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    28. client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    29. // Starts the download
    30. client.DownloadFileAsync(new Uri(DLSite + "" + match.Groups["name"]), saveDIR + "" + match.Groups["name"]);
    31. Console.Write(DLSite + "" + match.Groups["name"] + "\n");
    32. isDownload = true;
    33. }
    34. }
    35. }
    36. }
    37. }
    38. }
    39. Console.ReadLine();
    40. }
    Ich hab ja gesagt:

    ErfinderDesRades schrieb:

    Als erstes: solange du die zu downloadenden Daten nicht vollständig ermitteln kannst, brauchst du dir ums Gedownloade keinen Kopp zu machen.
    Also sieh erstmal zu, wie du an eine vollständige Liste der zu downloadenden Dateien kommst.
    (Übrigens besonders effizient wäre, wenn dein Webspace eine Inhalts-Verzeichnis-Datei bereitstellen könnte.)

    Die dann runterzuladen ist eine andere Sache, da kann ich sogar auf ein Sample verweisen, wo solch drin vorkommt: Async, Await und Task
    Ist allerdings vb, und ist mit http, nicht ftp.