none
C# FTP Request timeout mit embedded Device RRS feed

  • Frage

  • Hallo,

    ich habe hier ein Power Quality Messgerät, welches auf seiner SDKarte eine Reihe von Dateien mit Messdaten und anderem, z.B. Kurvenformen von Störungen etc. speichert. Diese Dateien müssen per FTP Verbindung heruntergeladen werden für weitere Verarbeitung.

    Das Problem ist, daß keine Verbindung zustande kommt, sondern immer nur eine Timeout Exception geworfen wird.

    Anfrage beim Hersteller ergab, daß für FTP bei Benutzung von FileZilla folgende Einstellungen getroffen werden müssen:

    - Transfer mode passiv

    - Anzahl simultaner Verbindungen auf "1" begrenzen

    Im FileZilla lässt sich das einstellen, und dann kann auch auf das Gerät mit FTP zugegriffen werden.

    In C# ist es nur möglich, den passiv mode zu verwenden. Ich habe nichts darüber gefunden, ob und wie man die Anzahl der simultanen Verbindungen (ich denke mal, es ist der CommandChannel und der TransferChannel gemeint) auf 1 begrenzen kann.

    Ohne diese Einstellungen kommt auch beim FileZilla meist noch nicht mal ein connect zustande.

    Zum Test benutze ich folgenden Code:

    FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://172.16.0.199/");
    request.UsePassive = true;
    request.Credentials = new NetworkCredential("PQube", "PQube");
    request.KeepAlive = true;
    request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
    FtpWebResponse response = null;
    try
    {
      response = (FtpWebResponse)request.GetResponse();
      Stream responseStream = response.GetResponseStream();
      StreamReader reader = new StreamReader(responseStream);
      Console.WriteLine(reader.ReadToEnd());
      Console.WriteLine("Directory List Complete, status {0}",         response.StatusDescription);
      reader.Close();
    responseStream.Close(); response.Close(); } catch (WebException web) { Console.WriteLine("Web Exception: " + web.Message); }

    Weiß jemand Rat ?


    Dienstag, 29. Januar 2013 11:20

Antworten

  • Hallo Marcel,

    Heureka!

    Endlich hat es funktioniert, nachdem ich den DataConnectionType des FtpClient von FtpDataConnectionType.PASV auf FtpDataConnectionType.PASVEX geändert habe !

    Jetzt geht der Connect durch, und auch die Directory entries kann ich empfangen.

    Vielen Dank !

    Donnerstag, 31. Januar 2013 14:22

Alle Antworten

  • Das Problem ist das FtpWebClient zum direkten download von Dateien gedacht ist. Es fehlt also wohl noch der Modus für Binary oder ASCII, d.h. request.UseBinary = false;.
    Dienstag, 29. Januar 2013 11:37
  • leider hilft auch das nicht, Schade.

    Dienstag, 29. Januar 2013 11:44
  • Hallo Gerhard,

    dann versuch's doch mal bitte mit ServicePoint.ConnectionLimit:

    request.ServicePoint.ConnectionLimit = 1;


    Der Standardwert ist 2, wenn ich mich nicht irre.

    P.S. Sollte das Problem weiter bestehen, muss festgestellt werden, an welchem Punkt dein Program aussteigt. Dazu erstellst Du eine Ablaufverfolgung. In der app.config:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.diagnostics>
       <sources>
            <source name="System.Net" tracemode="includehex" maxdatasize="1024">
              <listeners>
                <add name="System.Net"/>
              </listeners>
            </source>
            <source name="System.Net.Sockets">
              <listeners>
                <add name="System.Net"/>
              </listeners>
            </source>
            <source name="System.Net.Cache">
              <listeners>
                <add name="System.Net"/>
              </listeners>
            </source>
          </sources>
          <switches>
            <add name="System.Net" value="Verbose"/>
            <add name="System.Net.Sockets" value="Verbose"/>
            <add name="System.Net.Cache" value="Verbose"/>
          </switches>
          <sharedListeners>
            <add name="System.Net"
              type="System.Diagnostics.TextWriterTraceListener"
              initializeData="network.log"
            />
          </sharedListeners>
          <trace autoflush="true"/>
      </system.diagnostics>
      <startup> 
          <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
    </configuration>

    In den Projekteigenschaften, Registerkarte "Erstellen", muss dann noch die "TRACE-Konstante definieren"-Option aktiviert werden. Poste anschließend die anonymisierte network.log.

    Gruß
    Marcel



    Dienstag, 29. Januar 2013 12:07
    Moderator
  • Die Stelle im Quellcode, an der das testprogramm hängen bleibt, ist eindeutig die Zeile mit dem "GetResponse". Ich werde aber noch einen Trace versuchen.

    Zwischenzeitlich habe ich mir mal mit dem Wireshark angesehen, was da an Kommunikation läuft.

    Der FileZilla sendet zuerst einen tcp SYN zum Gerät, das antwortet mit 220: Service ready for new user. Anschliessend sendet FileZilla den Username, der mit "331: user name ok, need password" quittiert wird. Dann sendet FileZilla das Password, quittiert mit "230: user logged in".

    Anschliessend wird der ftp request "PWD" gesendet, der vom Gerät beantwortet wird.

    Mit dem Testprogramm dagegen:

    Das Programm kommt bis zu dem Punkt, wo vom Gerät die Meldung kommt: "220: Service ready for new User". Danach wird merkwürdigerweise vom PC ein tcp Ack und danach ein ftp RST, ACK gesendet ? Kein Username oder so, und dann ist Ende Gelände.

    Dienstag, 29. Januar 2013 13:23
  • Der letzte "RST ACK" stammt wohl vom Abbruch durch die Exception.

    Definitiv wird also vom request kein Login durchgeführt, trotz der Credentials ???

    Dienstag, 29. Januar 2013 14:13
  • Ja, die Credentials werden nach der 220-Antwort scheinbar nicht gesendet. Kann dir vielleicht eine Alternative anbieten:

    using System;
    using System.Net;
    using System.Net.FtpClient;
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                FtpClient ftp = new FtpClient();
                ftp.DataConnectionType = FtpDataConnectionType.PASV;
                ftp.Host = "172.16.0.199";
                ftp.Credentials = new NetworkCredential("PQube", "PQube");
                ftp.Connect();
                if (ftp.IsConnected)
                {
                    var workingDirectory = ftp.GetWorkingDirectory();
                    var items = ftp.GetListing(workingDirectory, FtpListOption.NameList);
                    foreach (var item in items)
                        Console.WriteLine(item.Name);
                }
                
                Console.ReadKey(true);
            }
        }
    }
    Klappt denn die Kommunikation mit dem Server von der Befehlszeileneingabe problemlos?
    Dienstag, 29. Januar 2013 16:20
    Moderator
  • Hallo Marcel,

    wo hast du den Namespace System.Net.FTPClient hergenommen ?

    ist bei mir nicht zu finden.

    Schöne Grüße, Gerhard

    Mittwoch, 30. Januar 2013 07:31
  • Hallo Gerhard,

    Das ist ein CodePlex-Projekt, den Link dazu findest Du im vorherigen Posting. Der Namensraum ist - zugegeben - etwas irreführend.

    Viele Grüße
    Marcel

    Mittwoch, 30. Januar 2013 07:47
    Moderator
  • Hallo Marcel,

    ich hab das verlinkte Projekt geladen, ich bekomme aber den namespace nicht in mein Projekt.

    Wenn ich die dll als Referenz einbinde, dann ist zunächst alles scheinbar in Ordnung, und ih kann die Using Direktive benutzen, auch der Typ wird highlighted. Beim nächsten build heisst es aber, daß es den Namespace System.Net.FtpClient nicht gäbe.

    Schöne Grüße, Gerhard

    Das oben hat sich erledigt: ich hatte .NET 4.0 ClientProfile angegeben;nach Änderung auf .NET 4.0 war das Problem weg.

    Leider hat sich dadurch in Bezug auf die Kommunikation nichts verbessert, obwohl ich auf Verdacht inzwischen das TCP Modul des Gerätes getauscht und die Firmware upgedatet habe, bleibt er immer noch bei den Credentials hängen.

    Donnerstag, 31. Januar 2013 13:50
  • Hallo Marcel,

    Heureka!

    Endlich hat es funktioniert, nachdem ich den DataConnectionType des FtpClient von FtpDataConnectionType.PASV auf FtpDataConnectionType.PASVEX geändert habe !

    Jetzt geht der Connect durch, und auch die Directory entries kann ich empfangen.

    Vielen Dank !

    Donnerstag, 31. Januar 2013 14:22