URLDownloadToFile / DeleteUrlCacheEntry mit FTP (mit Benutzername und Passwort)



  • Hallo,
    ich habe folgendes Problem: ich möchte Dateien von einem Server herunterladen. Dabei sollen die Dateien in jedem Fall erneut heruntergeladen werden, d.h. nicht aus dem Cache geholt werden.

    Ich benutze zum Herunterladen die Funktion URLDownloadToFile und zum Löschen des Caches die Funktion DeleteUrlCacheEntry.

    Das funktioniert bis jetzt perfekt mit dem HTTP-Protokoll. Allerdings möchte ich nun mit den Dateien auf einen FTP-Server umziehen. Das Herunterladen funktioniert an sich auch mit FTP, allerdings wird beim erneuten Download der Cache benutzt obwohl ich vorher die entsprechenden Einträge lösche. Im Code hat sich nur die URL geändert, sonst nichts.

    Allerdings wird beim Herutnerladen vom FTP-Server ein Benutzername und ein Passwort verwendet.

    Statt
    URLDownloadToFile(NULL,"http://<IP_ADRESSE>/<DATEINAME>",<LOKALER_PFAD>,0,NULL)
    schreibe ich nun eben
    URLDownloadToFile(NULL,"ftp://<USERNAME>:<PASSWORT>@<IP_ADRESSE>/<DATEINAME>",<LOKALER_PFAD>,0,NULL)

    In der Funktion DeleteUrlCacheEntry darf ich Benutzername und Passwort allerdings nicht mit angeben (hab ich irgendwo gelesen und funktioniert auch nicht wenn man es doch mit angibt)
    Also schreibe ich statt
    DeleteUrlCacheEntry("http://<USERNAME>:<PASSWORT>@<IP_ADRESSE>/<DATEINAME>")
    nur folgendes:
    DeleteUrlCacheEntry("ftp://<IP_ADRESSE>/<DATEINAME>")

    Ist das soweit wenigstens richtig?

    Ich habe auch eine Klasse geschrieben, die von IBindStatusCallback ableitet und alle Methoden überschrieben. Ich habe dort auch mit der Methode GetBindInfo und den Flags BINDF_NOWRITECACHE, BINDF_PRAGMA_NO_CACHE und BINDF_GETNEWESTVERSION herumgespielt. Das hat aber auch nicht geholfen.

    Komisch an der Sache ist, dass DeleteUrlCacheEntry bei den zwei kleineren Dateien (2 MB) "true" zurückgegeben wird und aber bei der größeren Datei (85 MB) kommt "false" zurück, GetLastError liefert in dem Fall Code 32, also ERROR_SHARING_VIOLATION. Die beiden kleineren Dateien werden beim nächsten mal wieder herutnergeladen, aber die große Datei ist sofort da. Daher, denke ich, wird die große Datei weiterhin aus dem Cache geholt.

    Weiß da jemand Bescheid was ich falsch mache? Es ist ja eigentlich nur ein anderes Protokoll. Nur die Sache mit dem Benutzername und Passwort könnte das Problem verursachen. Wenn ja, wie geht das dann?

    EDIT:
    Ich habe jetzt einen passworthgeschützten Bereich auf meinem HTTP-Server eingerichtet. Um von dort herunter zu laden gebe ich auch in der URL den Benutzername und das Passwort an, genauso wie ich es oben mit dem FTP-Protokoll beschrieben habe. Bei dem passwortgeschützten HTTP funktioniert es mit dem Löschen. Der einzige Unterschied, der nun also noch besteht ist, dass das FTP-Protokoll benutzt wird und die Domain bzw. die IP-Adresse, von der heruntergeladen wird.
    Ich hab hier im Forum einen Workaround gefunden, bei dem man hinten an die URL noch was dran hängt, was keine Auswirkung hat. Aber ich würde gerne das Problem gelöst haben anstatt es zu umgehen.

    MfG



  • Hallo nochmal,
    der Fehler lag wohl wo anders.

    Ich habe in meiner Anwenung einen Close-Button. Wenn der während des Downloads geklickt wird, wird die Anwendung beendet - und das auf ziemlich unsanfte Art: PostQuitMessage(0)

    Würde das erklären, warum beim nächsten Aufruf von DeleteUrlCacheEntry der Fehler-Code ERROR_SHARING_VIOLATION kommt?

    Außerdem kommt vom FTP-Server die Meldung, dass es bereits zu viele Connections von meiner IP Adresse gibt, sobald ich den Download fünf mal abgebrochen habe.

    Meine Frage ist nun: wie kann ich UrlDownloadToFile korrekt stoppen? Ich habe versucht, in jeder Methode von IBindStatusCallback den Wert S_FALSE zurück zu geben, sobald der Download gestoppt werden soll. Aber der lädt munter weiter herunter...

    Kann mir jemand sagen wie das geht?

    MfG



  • Ok, habe herausgefunden, dass ich nicht S_FALSE zurückgeben muss, sondern E_ABORT.

    Die Funktion UrlDownloadToFile wird dann auch sofort verlassen, aber trotzdem meckert der FTP-Server nach fünf Tests, dass zu viele Connections von meiner IP bestehen.

    Oder wird die Verbindung tatsächlich abgebaut und der FTP-Server merkt das nicht? Oder dem FTP-Server ist es egal ob der Download abgebrochen wurde und erlaubt trotzdem keine Neustarts des Downloads?

    Was kann ich tun?



  • Also ich habe es jetzt den Download vom FTP mit den Funktionen FtpOpenFile() und InternetReadFile() realisiert. Das funktioniert!!!

    InternetReadFile() befindet sich natürlich in einer Schleife. Wenn auf den Close-Button gedrückt wird, wird die Schleife verlassen und danach InternetCloseHandle() aufgerufen für die drei Handles, die während des Vorgangs erzeugt werden (müssen). Erst wenn das alles erledigt ist, wird PostQuitMessage(0) aufgerufen.

    So kann ich den Download munter 20-30 mal aufrufen (wahrscheinlich auch öfter, aber ich hatte kein bock noch weiter zu testen) und der FTP-Server nimmt weiterhin neue Vebindungen an. Sieht im Prinzip so aus (was wäre ein Thread ohne Code...?!):

    //Globale Variable:
    bool globalVar_downloadStoppen; //mit 'false' initialisiert
    bool globalVar_downloadBeendet; //mit 'false' initialisiert
    CRITICAL_SECTION globalVar_critSec;
    //------------------------------------------------------------------------------
    
    HINTERNET hiOpen = InternetOpenA("Meine_Anwendung",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    if(!hiOpen){MessageBoxA(NULL,"InternetOpen fehlgeschlagen","",MB_OK);}
    
    HINTERNET hiConnect = InternetConnectA(hiOpen,"server.abc",INTERNET_DEFAULT_FTP_PORT,"benutzername","passwort",INTERNET_SERVICE_FTP,INTERNET_FLAG_PASSIVE,kontext);
    if(!hiConnect){MessageBoxA(NULL,"InternetConnect fehlgeschlagen","",MB_OK);}
    
    HINTERNET hiFile = FtpOpenFileA(hiConnect,"Datei.dat",GENERIC_READ,FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_RELOAD,kontext);
    if(!hiFile){MessageBoxA(NULL,"FtpOpenFile fehlgeschlagen","",MB_OK);}
    
    char puffer[1024];
    DWORD dateiGröße = 12345;
    DWORD gelesenAktuell;
    DWORD gelesenDatei = 0;
    FILE* lokaleDatei = fopen("C:\\Datei.dat","wb");
    bool lokalVar_downloadStoppen = false;
    
    while(gelesenDatei < dateiGröße && !lokalVar_downloadStoppen)
    {
      InternetReadFile(hiFile,puffer,min(1024,dateiGröße-gelesenDatei),&gelesenAktuell);
      gelesenDatei += gelesenAktuell;
      fwrite(puffer,sizeof(char),gelesenAktuell,lokaleDatei);
      zeichneLadeBalken(gelesenDatei,dateiGröße);
      EnterCriticalSection(&globalVar_critSec);
      lokalVar_downloadStoppen = globalVar_downloadStoppen;
      LeaveCriticalSection(&globalVar_critSec);
    }
    
    fclose(lokaleDatei);
    InternetCloseHandle(hiFile);
    InternetCloseHandle(hiConnect);
    InternetCloseHandle(hiOpen);
    EnterCriticalSection(&globalVar_critSec);
    globalVar_downloadBeendet = true;
    LeaveCriticalSection(&globalVar_critSec);
    
    //Vor PostQuitMessage(0) wird gewartet bis globalVar_downloadBeendet a8f 'true' gesetzt wurde
    

    UrlDownloadToFile() beendet die Verbindung zum FTP-Server nicht korrekt . So sieht es für mich jedenfalls aus... Ich benutze prinzipiell den selben Shutdown-Mechanismus: Klick auf den Close-Button -> UrlDownloadToFile() verlassen -> dann erst PostQuitMessage(0). UrlDownloadToFile() wird verlassen indem in der OnProgress()-Methode E_ABORT zurückgegeben wird anstatt S_OK.

    Aber da kann ich ich meine Anwendung nur fünf mal starten und beenden. Beim sechsten mal kann keine Verbindung mehr zum FTP-Server aufgebaut werden. Der Server meldet "421 Too many connections (5) from this IP".

    Also Vorteil der jetzigen Variante ist, dass ich keine Probleme mehr hab mit dem Neustart meiner Anwendung und den Downloads.
    Nachteil: Ich bin mit meiner URL an das FTP-Protokoll gebunden. Ich muss eine Entscheidung implementieren, ob es FTP oder HTTP sein soll.
    Bei UrlDownloadToFile() konnte ich einfach irgendeine URL übergeben.

    MfG


Anmelden zum Antworten