Rubrik: Internet/Netzwerk | VB-Versionen: VB5, VB6 | 01.12.01 |
FTP - File Transfer Protokoll, Teil 2 Der zweite Teil unseres "FTP"-Workshops widmet sich nun dem Up- und Download von Dateien. Auch möchten wir Ihnen zeigen, wie sich ein abgebrochener Up- oder Download-Vorgang zu einem späteren Zeitpunkt wieder fortsetzen lässt. Somit sollten Sie am Ende dieses Workshops über alle Informationen verfügen, um Ihren eigenen FTP-Clienten zu programmieren. | ||
Autor: Dieter Otter / Matthias Volk | Bewertung: | Views: 27.247 |
Im ersten Teil unseres "FTP"-Workshops haben wir Ihnen die grundlegende Vorgehensweise für das Herstellen einer Verbindung zu einem externen FTP-Server, sowie alle hierfür notwendigen Befehle und Funktionen vorgestellt. Der zweite Teil widmet sich nun dem Up- und Download von Dateien. Auch möchten wir Ihnen zeigen, wie sich ein abgebrochener Up- oder Download-Vorgang zu einem späteren Zeitpunkt wieder fortsetzen lässt. Somit sollten Sie am Ende dieses Workshops über alle Informationen verfügen, um Ihren eigenen FTP-Clienten zu programmieren.
Kurzer Rückblick
Mit den aus Teil 1 vorgestellten Befehlen und Funktionen konnte bisher folgendes durchgeführt werden:
- Anmelden und Verbinden mit dem FTP-Sever
- Verzeichnisinformationen lesen und in einer Liste anzeigen
- Wechseln in über- und untergeordnete Verzeichnisse und Inhalt anzeigen
- Ermitteln der Dateigröße einer Datei
- Verbindung beenden
Was jetzt noch fehlt, sind die entsprechenden Befehle, um eine auf der Festplatte lokal gespeicherte Datei in ein Verzeichnis des FTP-Servers hochzuladen (Upload), sowie umgekehrt eine auf dem FTP-Server vorhandene Datei lokal auf die Festplatte zu speichern (Download).
Download einer Datei
Beginnen wir mit dem Download-Vorgang. Für den Download von Dateien benötigen wir ein drittes Winsock-Steuerelement. Wir nennen es DownSock. Voraussetzung für einen erfolgreichen Download ist, dass zunächst eine Verbindung zum FTP-Server hergestellt wurde. Nachdem wir uns also am FTP-Server angemeldet haben und die Verbindung zustande gekommen ist, müssen wir zunächst wieder einen eindeutigen Port für das Empfangen der Daten öffnen. Ach so, ja - zuvor setzen wir den Übertragungsmode noch auf Binary.
' Datei downloaden Friend Function DownloadFile(ByVal LocalFile As String, _ ByVal ServerFile As String, _ ByVal ServerFileSize As Long, _ Optional ByVal StartDownloadAt As Long = 0) Dim TmpPort As Long Dim TmpPortStr As String ' Servermodus auf Binär stellen If SendCommand(OvermitBinary, CommandOk, CommandOk, _ CommandFail) = False Then Exit Function NewUniquePort: ' Port öffnen (für das Empfangen von Daten) TmpPort = 0 ' Neuen Port ermitteln Call GetNewPort(TmpPort, TmpPortStr) ' Neuen Port öffnen With Downsock .Close .LocalPort = TmpPort .Listen End With ' neu geöffneten Port dem Server mitteilen If SendCommand(SetPort & TmpPortStr, CommandOk, _ CommandOk, CommandFail, 0&, "Neuer Port geöffnet") = False Then Exit Function End If ' Download-Startposition setzen If SendCommand(ResumeTransfere & StartDownloadAt, _ ResumingSupportet, CommandOk, _ CommandNotImplemented) = False Then Exit Function ' Progressbar einstellen ' siehe Workshop-Projekt ' lokale Datei öffnen/erstellen FFile = FreeFile Open LocalFile For Binary As FFile Seek #FFile, StartDownloadAt + 1 ' Download-Anfrage an Server senden TAbort = False TotalBytes = ServerFileSize OvermittedBytes = StartDownloadAt SendCommand Download & ServerFile, TransferComplete, _ TransferComplete, DataConnectionClosed, TransferStart ' Warten bis das letzte Datenpäckchen übermittelt ' wurde Do DoEvents Loop Until Downsock.State <> sckConnected ' Socket schließen Downsock.Close ' Neue Datei schließen If FFile <> -1 Then Close FFile FFile = -1 End If ' Falls abgebrochen wurde If TAbort = True Then ... End If ' Falls die Verbindung zur Datenleitung nicht ' aufgebaut werden konnte nochmals versuchen If LastServerCmd = DataConnectionError Then GoTo NewUniquePort End Function
Wie Sie bereits an der Parameter-Deklaration der Prozedur DownloadFile erkennen können, lässt sich hier optional angeben, ob der Datei-Download ab einer bestimmten Datei-Position fortgesetzt werden soll (für den Fall, dass ein voriger Download abgebrochen wurde). Hierzu muss die entsprechende Position im Parameter StartDownloadAt angegeben werden.
Nach dem Senden der Download-Anfrage muss zunächst auf die Server-Antwort gewartet werden:
' Server-Verbindungsaufbau "genehmigen" Private Sub DownSock_ConnectionRequest(ByVal requestID As Long) With Downsock If .State = sckListening Then .Close Do DoEvents Loop Until .State = sckClosed .Accept requestID End If End With End Sub
Immer wenn der Server uns Daten schickt, wird das DataArrival-Ereignis ausgelöst. Hier müssen wir nun die empfangenen Daten speichern (an die lokal geöffnete Datei "anhängen"). Desweiteren bietet sich hier auch bestens die Gelegenheit, eine evtl. vorhandene Statusanzeige zu aktualisieren:
' Server Daten erreichen uns Private Sub DownSock_DataArrival(ByVal bytestotal As Long) Dim TmpData As String ' Falls keine Bytes oder lokale Datei nicht ' geöffnet, Prozedur verlassen If bytestotal = 0 Or FFile = -1 Then Exit Sub ' Bisher empfangene Bytes aufaddieren OvermittedBytes = OvermittedBytes + bytestotal ' Daten an die lokal geöffnete Datei "anhängen" Downsock.GetData TmpData Put #FFile, , TmpData ' Download-Fortschritt aktualisieren ShowProgress picProgress, OvermittedBytes, 0, TotalBytes End Sub
Abbrechen eines Up-/Downloads
Natürlich sollten wir auch eine Möglichkeit vorsehen, dass man einen Up- oder Download jederzeit manuell (per Knopdruck) abbrechen kann. Hierzu speichern wir uns den Abbruch in der Variablen TAbort. Während des Up- bzw. Downloads wird diese Variable ständig abgefragt, so dass die Schleife für das Uploaden bzw. Downloaden der Datenpakete beendet werden kann.
' Dateiübertragung abbrechen Friend Function TransfereAbort() ' Abbruch-Kommando an den Server schicken SendCommand AbortTransfere, TransferComplete, _ TransferComplete, -1& ' Abbruch-Variable auf True setzen TAbort = True End Function
Upload einer Datei
Für den Upload-Vorgang verwenden wir ebenfalls das "neue" Downsock-Control. Der Upload selbst erfolgt immer in kleinen Datenpaketen, welche nach und nach an den FTP-Server geschickt werden. Jedesmal, wenn wir ein Datenpaket verschickt haben, müssen wir warten, bis der Server die Daten erhalten und bestätigt hat. Dann folgt das nächste - eben solange, bis die gesamte Datei auf den Server "hochgeladen" wurde. Sind alle Daten übertragen, wird die Datenverbindung wieder geschlossen. Natürlich möchten wir auch hier wieder während des Upload-Vorgangs den Fortschritt in Form einer Balkengrafik anzeigen. Ebenso soll es auch möglich sein, den Vorgang jederzeit abbrechen zu können.
' Datei "uploaden" Friend Function UploadFile(ByVal LocalFile As String, _ ByVal ServerFile As String, _ Optional ByVal StartUploadAt As Long = 0) Dim TmpPort As Long Dim TmpPortStr As String Dim SendBuff As String ' Servermodus auf Binär stellen If SendCommand(OvermitBinary, CommandOk, CommandOk, _ CommandFail) = False Then Exit Function NewUniquePort: ' Port öffnen (für das Senden der Daten) TmpPort = 0 ' Neuen Port ermitteln Call GetNewPort(TmpPort, TmpPortStr) ' Neuen Port öffnen With Downsock .Close .LocalPort = TmpPort .Listen End With ' neu geöffneten Port dem Server mitteilen If SendCommand(SetPort & TmpPortStr, CommandOk, CommandOk, _ CommandFail, 0&, "Neuer Port geöffnet") = False Then Exit Function End If ' Upload-Startposition setzen SendCommand ResumeTransfere & StartUploadAt, _ ResumingSupportet, CommandOk, CommandNotImplemented ' Progressbar einstellen ' siehe Workshop-Projekt ' lokale Datei öffnen FFile = FreeFile Open LocalFile For Binary As FFile Seek #FFile, StartUploadAt + 1 ' Anfrage an Server senden TAbort = False TotalBytes = LOF(FFile) OvermittedBytes = StartUploadAt If SendCommand(Upload & ServerFile, TransferStart, _ TransferStart, PermissionDenied) = False Then ' Zugriff verweigert (auf der Server-Seite) ... Exit Function End If ' Warten bis die Datenleitung verbunden ist Dim TimeOut As Long TimeOut = GetTickCount + 1000 * ConnectTimeOut Do DoEvents Loop Until Downsock.State = sckConnected Or _ TimeOut < GetTickCount / 1000 ' TimeOut überschritten! If Downsock.State <> sckConnected Then Exit Function ' Alle Daten senden und warten bis die Daten den ' Server erreichen PacketSend = True Do DoEvents ' Wenn vorheriges Päckchen beim Server ist, ' neues Daten-Päckchen senden If PacketSend = True And _ OvermittedBytes <> TotalBytes Then ' Puffergröße festlegen If TotalBytes - OvermittedBytes < SendBufferLenght Then SendBuff = Space(TotalBytes - OvermittedBytes) Else SendBuff = Space(SendBufferLenght) End If ' Übertragene Bytes aufaddieren OvermittedBytes = OvermittedBytes + Len(SendBuff) ' Progressbar aktualisieren ShowProgress picProgress, OvermittedBytes, 0, TotalBytes ' Daten aus der Datei lesen Get #FFile, , SendBuff ' Daten an den Server schicken If TAbort = True Then Exit Do PacketSend = False Downsock.SendData SendBuff End If Loop Until TotalBytes = OvermittedBytes And PacketSend = True ' Socket schließen Downsock.Close SendCommand "", TransferComplete, TransferComplete, -1& ' Für den nächsten Down-/Upload zurücksetzen OvermittedBytes = 0 TotalBytes = 0 ' Datei schließen If FFile <> -1 Then Close FFile FFile = -1 End If ' Falls abgebrochen wurde If TAbort = True Then ... End If ' Falls die Verbindung zur Datenleitung nicht ' aufgebaut werden konnte, nochmals versuchen If LastServerCmd = DataConnectionError Then GoTo NewUniquePort End Function
Wie bereits schon bei der Download-Prozedur lässt sich auch bei ein abgebrochener Upload-Vorgang ab einer bestimmten Dateiposition fortsetzen. Hierzu muss einfach dem Parameter StartUploadAt die entsprechende Bytes-Position innerhalb der Datei mitgeteilt werden.
Immer wenn wir (besser gesagt das Winsock-Control - in unserem Fall das Downsock-Control) ein Datenpaket verschickt haben, wird das Ereignis SendComplete ausgelöst. Dies ist dann auch die "richtige Stelle", an der wir die Variable PaketSend auf True setzen, so dass sich im Anschluss daran, das nächste Datenpaket auf den Weg machen kann
' Wenn beim Upload die Daten gesendet sind, ' Variable auf True stellen Private Sub DownSock_SendComplete() PacketSend = True End Sub
Alle wichtigen Kommandos an den Server
Ein richtiger FTP-Client kann natürlich noch mehr, als nur Verzeichnisse anzeigen und Dateien up- und downzuloaden. Standard-Befehle, wie Dateien und Verzeichnisse löschen oder Dateien und Verzeichnisse umbenennen sollte demnach zur "Grundausstattung" gehören.
Alle diese Befehle sind FTP-Kommandos, welche an den Server geschickt werden. Hierbei handelt es sich um Strings (z.B. STOR - um Dateien zu senden), welche immer mit einem vbCrLf-Zeichen beendet werden müssen. Erwartet ein Kommando einen Parameter, wie z.B. den Verzeichnisnamen beim Wechseln des Verzeichnisses, so wird dieser Paramater getrennt durch ein Leerzeichen direkt hinter dem Kommando angegeben.
Nachfolgend eine Liste mit den wichtigsten FTP-Kommandos:
Kommando | Parameter | Beschreibung |
USER | Erwartet einen gültigen Benutzernamen oder "Anonymous" für die Anmeldung am Server | Dieses Kommando wird direkt nach der Willkommensnachricht erwartet und teilt dem Server den Benutzernamen mit. |
PASS | Erwartet ein Passwort. Gültige Werte sind "Pass", eine Email-Adresse oder zugelassene Passwörter für den Benutzernamen | Dieses Kommando teilt dem Server das Passwort mit. |
QUIT | Kein Parameter | Verbindung zum Server trennen |
PWD | Kein Parameter | Server übermittelt das aktuelle Verzeichnis |
LIST | Kein Parameter | Anforderung der Verzeichnisstruktur des aktuellen Verzeichnisses |
TYPE | "A" für Ascii-Übertragungsmodus oder "I" für Binär-Übertragungsmodus | Festlegen des Übertragungsmodus |
PORT | Erwartet einen String zum Verbinden mit einem Port | Der Server verbindet sich mit diesem Port - und zwar beim nächsten Up-/Download oder Übermitteln eines Verzeichnisses |
CWD | Erwartet einen rekrusiven oder kompletten Dateipfad | Der Server wechselt in das im Parameter angegebene Verzeichnis |
CDUP | Kein Parameter | Der Server wechselt in das übergeordnete Verzeichnis |
SIZE | Erwartet einen Dateinamen mit kompletten Pfadangaben | Der Server übermittelt die Dateigröße der angegeben Datei (in Bytes) |
REST | Erwartet eine Dateiposition | Der Server beginnt den nächsten Up-/Download an der angegebenen Dateiposition |
RETR | Erwartet einen Dateinamen mit kompletten Pfadangaben | Der Server sendet die angegebene Datei über den zuvor definierten Datenport |
ABOR | Kein Parameter | Der Server schliesst den aktuellen Datenport und beendet den laufenden Up-/Downloadprozess |
STOR | Erwartet einen Dateinamen mit kompletten Pfadangaben | Der Server öffnet den Datenport und speichert die ankommendenen Daten in die angegebene Datei |
RNFR | Erwartet einen existierenden Dateinamen mit kompletten Pfadangaben | Legt eine Datei fest, die umbenannt oder verschoben werden soll (Rename From) und wartet anschliessend auf das Kommando RNTO |
RNTO | Erwartet einen Dateinamen mit kompletten Pfadangaben | Legt den neuen Dateinamen fest (Rename To). Der Server benennt die zuvor über RFNR festgelegte Datei in den angegebenen Dateinamen um und/oder kopiert diese in das angegebene Verzeichnis |
MKD | Erwartet vollständigen Verzeichnisnamen | Erstellt ein neues Verzeichnis |
RMD | Erwartet einen existierenden Verzeichnisnamen mit vollständiger Pfadangabe | Löscht ein Verzeichnis (ACHTUNG: Das Verzeichnis kann nur gelöscht werden, wenn sich keine Dateien und/oder Ordner mehr in diesem befinden) |
DELE | Erwartet einen existierenden Dateinamen mit vollständiger Pfadangabe | Löscht die im Parameter angegebene Datei |
Alle wichtigen Server-Rückmeldungen
Nach dem Senden eines Kommandos an den Server (siehe Tabelle FTP-Kommandos) muss immer auf die Server-Anwort gewartet werden. Hierbei handelt es sich um eine dreistellige Zahl, die einen Status oder eine erwartete Aktion beschreibt. Serverkommandos sind nur abgeschlossen, wenn der Zahl ein Leerzeichen folgt. Abgeschlossen sind die Kommandos wieder durch ein vbCrLf-Zeichen.
Enthält die Server-Rückmeldung zusätzlicher Parameter, so sind diese durch ein Leerzeichen getrennt direkt hinter der dreistelligen Zahl angegeben.
Kommando | Parameter | Beschreibung |
150 | Der Server hat sich erfolgreich mit dem Datenport verbunden | |
200 | Ein Kommando wurde erfolgreich ausgeführt | |
213 | Dateigröße in Bytes | Server hat die Dateigröße übermittelt |
220 | Willkommensnachricht | Der Server sendet dieses Kommando direkt nachdem eine Verbindung hergestellt wurde |
226 | Der Server hat alle Daten über den Datenport übertragen | |
230 | Das Passwort wurde akzeptiert. Der Client ist nun erfolgreich eingeloggt. | |
231 | Der Benutzername wurde akzeptiert und das Passwort wird anschliessend erwartet | |
250 | Verzeichnispfad | Eine Verzeichnisfunktion war erfolgreich |
257 | Dateipfad | Dateiaktion war erfolgreich |
321 | Das Passwort wurde nicht akzeptiert, die Verbindung wird hierbei nicht getrennt. | |
321 | Der Benutzername wurde nicht akzeptiert, die Verbindung wird hierbei nicht getrennt | |
350 | Das Fortsetzen eines Down-/Uploads wird unterstützt und beginnt an der übermittelten Position | |
421 | Der Server hat nach einer zu langen Ruhephase die Verbindung getrennt | |
425 | Der Server konnte sich nicht mit dem Datenport verbinden | |
426 | Grund | Der Server hat aus irgendeinem Grund die Datenleitung getrennt |
500 | Grund | Ein Kommando konnte nicht ausgeführt werden |
501 | Der Benutzer hat nicht die Rechte, um die Aktion auszuführen | |
504 | Der Server "versteht" das angegebene Kommando nicht | |
530 | Grund für die Zugangsverweigerung | Aus einem bestimmten Grund wurde das "Einloggen" nicht genehmigt |
550 | Der Benutzer hat nicht die Rechte, um die Aktion auszuführen |
Zusammenfassung
Wir hoffen Ihnen mit unserem FTP-Workshop einen Einblick in die Vorgehens- und Arbeitsweise eines FTP-Client Programms gegeben zu haben. Mit dem in den beiden Teilen vermittelten Wissen, Befehlen und Funktionen, sollten Sie nun in der Lage sein, Ihren eigenen FTP-Clienten zu programmieren. Einen Ansatz hierfür bekommen Sie, wenn Sie sich unser Demo-Projekt zum FTP-Workshop downloaden.
Themen aus Teil 1:
- Anmelden und Verbinden mit dem FTP-Sever
- Verzeichnisinformationen lesen und in einer Liste anzeigen
- Wechseln in über- und untergeordnete Verzeichnisse und Inhalt anzeigen
- Verbindung beenden
Themen aus Teil 2:
- Download von Dateien
- Upload von Dateien
- Abbrechen und Fortsetzen eines Up-/Downloads
- Wichtige Kommandos an den Server
- Rückgabewerte vom Server
Hinweis zum Abschluss
Bitte beachten Sie, dass das Debugging des Projekts bei laufender Server-Verbindung und Daten-Übertragung sehr schwierig ist, da ankommende Serverdaten im "Speicher-Nirvana" landen, wenn sich der Debugger in der Ruhephase befindet!
Das Beispielsprojekt zum Teil 2 des FTP-Workshops zeigt, wie man sich mit einem FTP-Server verbindet und sich dann innerhalb des Server-Verzeichnisses bewegen kann (also Verzeichnisse und Dateien anzeigen, inkl. Verzeichniswechsel). Zusätzlich lassen sich Dateien up-/ und downloaden.