1. Einleitung
Nach dem Tutorial über das Winsock Array möchte ich euch in diesem Tutorial noch zeigen wie einfach es ist eine Datei per Winsock zu versenden.
Viele sources die verbreitet werden sind entweder schwer zu verstehen oder nutzen die Technik jedes Byte einzeln zu versenden, was natürlich enorme Zeit braucht bei größeren Dateien.
Ich werde euch eine viel einfachere Technik an einem simplen Beispiel zeigen, die ich benutze.
Benötigen werdet ihr:
Beim Client:
1. 1x Common Dialog Control (Im Code als „cdlg“ abgekürzt)
2. 1x Button (Command1)
3. 1x Winsock Control (ws)
4. 1x Label (Label1)
Beim Server:
1. 1x Button (Command1)
2. 2x Label (Label1 und Label2)
3. 1x Winsock Control (ws)
2. Client - Dateiversand
Den Client werden wir so coden, dass er für den Dateiversand zuständig ist.
Damit wir überhaupt mal Verbindungen entgegen nehmen können müssen wir das Winsock Control auf Listen setzen.
Code:
Private Sub Form_Load()
ws.LocalPort = 2222
ws.Listen
End Sub
Und eingehende Verbindungen akzeptieren wir hiermit.
Code:
Private Sub ws_ConnectionRequest(ByVal requestID As Long)
ws.Close
ws.Accept requestID
Label1.Caption = "Connection established"
End Sub
Damit wir auch sehen ob eine Verbindung besteht, wird gleich in Label1 eine Message ausgegeben.
Das selbe wenn eine Verbindung geschlossen wird.
Code:
Private Sub ws_Close()
Label1.Caption = "Connection lost"
End Sub
Das waren jetzt mal so die Standard Sachen für eine simple Winsock Verbindung.
Jetzt benutzen wir noch das Common Dialog Control im Button, damit ihr später einfach eine Datei aussuchen könnt.
Code:
Private Sub Command1_Click()
On Error GoTo Err:
With cdlg
.CancelError = True
.ShowOpen
If SendFile(.FileName) Then GoTo Err:
End With
Exit Sub
Err:
Call MsgBox("Error while sending the file!", vbCritical)
End Sub
Bis jetzt sollte eigentlich alles ohne Erklärungen klar sein. Ansonsten solltet ihr euch vorher andere Tuts ansehen, die euch mehr Basiswissen übers Winsock vermitteln.
Und jetzt kommen wir zum eigentlichen code. Jetzt kümmern wir uns um die Funktion Sendfile, die in Command1 aufgerufen wird.
Code:
Private Function SendFile(ByVal Filepath As String) As Boolean
'Hier wird die Datei versendet
Dim buffer As String, pos As Long, bytes As Long, AllComplete As Boolean
'Die Schleife läuft so lange, bis die Datei versendet wurde
Do
If (LOF(1) - pos) > bytes Then
'Teil der Datei einlesen
buffer = Space(bytes)
Get #1, pos, buffer
pos = pos + bytes
Else
bytes = (LOF(1) - pos) + 1
buffer = Space(bytes)
Get #1, pos, buffer
AllComplete = True
End If
'Daten senden
ws.SendData (buffer)
buffer = ""
'Warten bis der Teil gesendet wurde
Do
DoEvents
Loop Until SendComplete
Loop Until AllComplete
Close
Call MsgBox("Sending complete")
End Function
Erklärung zur Funktion
Im Grunde ist es sehr einfach.
Der Code funktioniert so, dass er die Datei Stückchenweise einliest und versendet.
Da das Winsock Control immer nur eine gewisse Menge an Bytes auf einmal versenden kann (65535Bytes max), können wir auch nicht größere Stücke auslesen.
Hier mal die wichtigsten Variablen:
pos zeigt immer unsere letze Position in der Datei an. Mit 1 fangen wir natürlich an.
bytes übergibt die Anzahl an Bytes, die immer ausgelesen werden sollen.
AllComplete ist True, wenn die komplette Datei versendet wurde.
SendComplete ist True, wenn ein Teil der Datei versendet wurde.
Filepath ist natürlich der Pfad zur Datei, die gesendet werden soll.
buffer ist der Zwischenspeicher für unsere Teile der Datei.
Und jetzt erkläre ich noch die wichtigen Zeilen.
Code:
If (LOF(1) - pos) > bytes Then
Diese If Abfrage überprüft ob die noch zu auslesenden Bytes mehr sind, als in bytes drinnen steht.
Wozu? Ganz einfach.
Wir wollen immer 65535Bytes auslesen. Wenn wir aber ans Ende der Datei kommen und nur noch z.B. 821Bytes zum auslesen sind, würden wir beim einlesen aus der Datei Blödsinn erhalten oder sogar einen Fehler.
Und wenn also weniger als 65535Bytes übrig sind zum auslesen, dann wird die Anzahl der restlichen Bytes an die Variable bytes übergeben.
Wir benutzen eine string Variable und nicht eine byte, so wie in vielen anderen sources.
Mit Get können wir unseren Teil einlesen. Aber man kann nur sagen, von wo er zum einlesen anfangen soll. Natürlich von pos.
Aber man kann nicht angeben, wie viel er einlesen soll.
Deshalb füllen wir die Variable buffer vorher mit sovielen Leerzeichen wie in bytes drinnen steht.
Stellt euch den string am besten wie eine leere Flasche vor, die sich bis zum Rand füllt wenn ihr sie unters Wasser haltet. Mehr passt einfach nicht rein.
Wenn wir also buffer mit genau 65535 Leerzeichen füllen, passt auch nicht mehr hinein.
Und in der Zeile „pos = pos + bytes“ wird einfach die letze Position aktualisiert, damit wir beim einlesen des nächsten Teiles wissen wo wir zuletzt waren.
Und jetzt kommt noch etwas sehr wichtiges.
Code:
Do
DoEvents
Loop Until SendComplete
Ich weiß. Sieht nicht wichtig aus, ist es aber.
Diese Schleife läuft solange, bis die Boolean Variable SendComplete True ist.
Diese Variable müsst ihr Global deklarieren.
Und dann müssen wir sie noch in die Sub ws_SendComplete() einfügen.
Code:
Private Sub ws_SendComplete()
SendComplete = True
End Sub
Wenn ein Teil versendet wurde, wird diese Sub ausgelöst und unsere Variable auf True gesetzt.
Und das war es auch schon mit dem Klienten.
3. Server - Dateiempfang
Hier mal die Grundlegenden Sachen.
Code:
Private Sub Command1_Click()
ws.Connect "127.0.0.1", 2222
End Sub
Private Sub ws_Close()
Label1.Caption = "Connection lost"
End Sub
Private Sub ws_Connect()
Label1.Caption = "Connection established"
End Sub
Und hier die Sub zum empfangen der Datei.
Code:
Private Sub ws_DataArrival(ByVal bytesTotal As Long)
Dim buffer As String
ws.GetData buffer
Open (App.Path & "\test.exe") For Binary As #1
Put #1, LOF(1) + 1, buffer
buffer = ""
Close
End Sub
In buffer empfangen wir die einzelnen Teile.
Und mit Put #1, LOF(1) +1, buffer schreiben wir jeden Teil ans Ende der Datei.
Zur Sicherheit leeren wir dann noch die Variable buffer
4. Fazit
Wie ihr seht ist es also gar nicht so schwer.
Natürlich ist das Beispiel sehr simple. Aber ich hoffe, dass ich euch ein wenig die Funktionsweise eines Datentransfers vermitteln konnte.
Hier habe ich auch noch den Beispielsource als Download für euch.
Download: Link
pw: vb-x.org
mfg, ZiG _________________
Zuletzt bearbeitet von ZiG_ am 15.11.2007, 17:32, insgesamt einmal bearbeitet
Und wieder mal einen Heftigen Applaus für: ZiG :respekt:
das ist ja mal ein Beispiel, dass bestimmt vielen helfen wird.
Und dazu noch sehr gut erklärt.
Wenn ich einen Hut aufhätte zöge ich ihn jetzt vor dir, da ich aber keinen habe, lasse ich ihn auf...
Trotzdem Weiter So, ZiG! _________________ Wie findet ihr meine Sig?
r4z3r_ « Webmaster »
Anmeldedatum: 06.02.2007 Beiträge: 252
Verfasst am: 09.08.2007, 11:42
wie kannst du einen hut auflassen den du nicht hast?^^
naja wieder ein tolles tut
*auch applaudir* :biggthumpup:
Archetype_ Newbie
Anmeldedatum: 30.08.2007 Beiträge: 8
Verfasst am: 30.08.2007, 14:23
Soweit ich das sehe wird die funktion sendfile in einer endlosschleife stecken bleiben , da sendcomplete nie auf true gesetzt wird (im gegensatz zu allcomplete ) .
vielleicht stell ich mich auch nur dumm an , bei mir gehts jedenfalls nicht , die funktion hängt sich auf und die übertragenen dateien sind 0 kb groß .
wäre dir aber trotzdem dankbar wenn du zurückposten würdest , sieht generell sehr brauchbar aus
Soweit ich das sehe wird die funktion sendfile in einer endlosschleife stecken bleiben , da sendcomplete nie auf true gesetzt wird (im gegensatz zu allcomplete ) .
vielleicht stell ich mich auch nur dumm an , bei mir gehts jedenfalls nicht , die funktion hängt sich auf und die übertragenen dateien sind 0 kb groß .
wäre dir aber trotzdem dankbar wenn du zurückposten würdest , sieht generell sehr brauchbar aus
Code:
Do
DoEvents
Loop Until SendComplete
Hast du auch das:
[vb:1:0323a20b93]Private Sub ws_SendComplete()
SendComplete = True
End Sub[/vb:1:0323a20b93]
eingefügt? weil ZiG hat ja erklärt das diese Schleife dazu da ist dass das Programm wartet bis die Daten fertig gesendet wurden, und das wird in der Variable SendComplete gespeichert, sie wird mit der oben geposteten Sub auf True gesetzt wenn die Daten fertig gesendet sind.
Archetype_ Newbie
Anmeldedatum: 30.08.2007 Beiträge: 8
Verfasst am: 30.08.2007, 18:22
ok ich war blind
danke
nochwas , aus irgendeinem Grund sind bei mir übertragenen Daten nie größer als 8 kb und somit meist fehlerhaft .
kann mir jemand erklären warum ?
Edit : auch das hat sich egrade geklärt , ist heute anscheinend nicht so mein tag ^^
Crypt0r_ Newbie
Anmeldedatum: 02.09.2007 Beiträge: 6
Verfasst am: 21.11.2007, 18:51
diese Zeile verstehe ich überhaupt nicht:
Code:
If SendFile(.FileName) Then GoTo Err:
Wozu ist die da?
ZiG_ Überflieger
Anmeldedatum: 07.03.2007 Beiträge: 1248
Verfasst am: 21.11.2007, 19:23
Hmm, kann ich nicht mehr genau sagen was ich mir bei dem Aufruf gedacht habe.
Jedenfalls wird die Funktion SendFile aufgerufen und der Dateipfad übergeben.
Da SendFile Als Boolean deklariert ist, könnte sie wenn man es so programmiert entweder True oder False zurückgeben.
Ich hab das scheinbar vergessen und wenn man es genau will sollte es evt. so heißen.
Code:
If Not SendFile(.FileName) Then GoTo Err:
Und in der Funktion Sendfile dann einfach True wenn es geklappt hat zurückgeben. Ansonsten False.
Oder das ganze überhaupt einfach weglassen. _________________ Wer nicht auf seine Weise denkt, denkt überhaupt nicht. (Oscar Wilde)
DimaMa_ Newbie
Anmeldedatum: 12.04.2008 Beiträge: 4
Probleme mit Winsock! Verfasst am: 23.04.2008, 19:05
Ich habe brobleme mit meiner sinconsole .
der server öffnet das test.exe aber schreibt iwie nichts rein (alles versucht 2 winsockets,2ports) hoffnungslos bitte helft mal .
ZiG_ Überflieger
Anmeldedatum: 07.03.2007 Beiträge: 1248
Verfasst am: 23.04.2008, 19:09
Erstell bitte dazu einen Thread in "Fragen und Antworten" _________________ Wer nicht auf seine Weise denkt, denkt überhaupt nicht. (Oscar Wilde)
DimaMa_ Newbie
Anmeldedatum: 12.04.2008 Beiträge: 4
Bei mir kommet ein fehler Verfasst am: 24.04.2008, 18:07
Bei mir kommt ein Fehler ZiG nachdem ich das einfüge:
Private Sub Winsock1_SendComplete()
SendComplete = True
End Sub
_________________
ZiG_ Überflieger
Anmeldedatum: 07.03.2007 Beiträge: 1248
Verfasst am: 24.04.2008, 18:42
Dann hast du den selben Event wahrscheinlich schonmal erstellt.
Und wie gesagt. Erstell zu Fragen bitte einen Thread in "Fragen und Antworten"! _________________ Wer nicht auf seine Weise denkt, denkt überhaupt nicht. (Oscar Wilde)