Winsock sendet langsam

Hey,

leider schon mein zweites Problem in zwei Tagen.
Es handelt sich um einen Filetransfer.
Wenn ich auf meinem Rechner das Programm zweimal starte und eine 4 MB Datei „versende“, dann dauert das ganze 30 Minuten.

Das Programm hängt aber nicht in irgendwelchen Schleifen, sondern bleibt bei der Ausführung über eine Sekunde bei „Winsock.SendData“ hängen. Ich habe absolut keine Ahnung, warum das so lange dauert.
Sind 1024 Byte als Block etwa zu groß?

Ich poste zum besseren Verständis mal den Code:


'Gilt für beide

Const Block = 1024

'Beim Sender

Private strFile As String

Private Sub sendfile()
Dim sData As String
Dim intDateiNr As Integer
intDateiNr = FreeFile

Open strFile For Binary Access Read As #intdateinr

Do While Not EOF(intdateinr)
sData = Input(Block, #intdateinr)
wsckFile.SendData sData
DoEvents
Loop
Close #intdateinr
End Sub


'Beim Empfänger
Private pos As Long
Private strFile As String

Private Sub wsckfile_DataArrival(ByVal bytesTotal As Long)
Dim BlocksCount As Integer
Dim intNewFile As Integer
Dim Data As String
BlocksCount = bytesTotal / Block

If pos = 0 Then
pos = 1
End If
wsckFile.GetData Data
intNewFile = FreeFile
For i = 1 To BlocksCount
Open strFile For Binary Access Write As #intNewFile
Seek #intNewFile, pos
Put #intNewFile, , Left(Data, Block)
Close #intNewFile
pos = pos + Block
If Len(Data) > Block then
Data = Mid(Data, Block + 1)
End if
Next i
End Sub

Vielen Dank im Vorraus.

MfG Hendrik Hilleckes

Hallo Hendrik,

leider schon mein zweites Problem in zwei Tagen.
Es handelt sich um einen Filetransfer.

Von dem ersten habe ich leider nichts mitbekommen. Hast du es gelöst oder sind noch Fragen offen?

Wenn ich auf meinem Rechner das Programm zweimal starte und
eine 4 MB Datei „versende“, dann dauert das ganze 30 Minuten.

Was verstehst du unter 2 mal?
2 mal hintereinander und 2 mal zur gleichen Zeit?
Aber 30 Minuten für 4 MB ist schon heftig!!
Was für eine Abindung haben denn beide Anschlüsse? ( DSL xxx ?)
Wie ist die Up sowie Download Geschwindigkeit beider Rechner?

Das Programm hängt aber nicht in irgendwelchen Schleifen,
sondern bleibt bei der Ausführung über eine Sekunde bei
„Winsock.SendData“ hängen.

Sendest du die Daten im Internet oder übers LAN?

Ich habe absolut keine Ahnung,
warum das so lange dauert.

Na schauen wir einmal!

Sind 1024 Byte als Block etwa zu groß?

Nein die kann man noch höher setzen!

Ich poste zum besseren Verständis mal den Code:


'Gilt für beide

Const Block = 1024

'Beim Sender

Private strFile As String

Private Sub sendfile()
Dim sData As String
Dim intDateiNr As Integer
intDateiNr = FreeFile

Open strFile For Binary Access Read As #intdateinr

Do While Not EOF(intdateinr)
sData = Input(Block, #intdateinr)
wsckFile.SendData sData
DoEvents
Loop
Close #intdateinr
End Sub

Warum so umstaendlich?
Was ist wenn ein ungültiger Wert gelesen wird?
Warum das DoEvents?


'Beim Empfänger
Private pos As Long
Private strFile As String

Private Sub wsckfile_DataArrival(ByVal bytesTotal As Long)
Dim BlocksCount As Integer
Dim intNewFile As Integer
Dim Data As String
BlocksCount = bytesTotal / Block

If pos = 0 Then
pos = 1
End If
wsckFile.GetData Data
intNewFile = FreeFile
For i = 1 To BlocksCount
Open strFile For Binary Access Write As #intNewFile
Seek #intNewFile, pos
Put #intNewFile, , Left(Data, Block)
Close #intNewFile
pos = pos + Block
If Len(Data) > Block then
Data = Mid(Data, Block + 1)
End if
Next i
End Sub

Hier hast du aber maechtige Böcke drinnen.
Schauen wir uns das mal genauer an.
Wir senden mal 4 MB! Das bedeutet 4*1024*1024=4194304 Bytes!
Bei einer Blockgrösse von 1024 waeren das 4194304 / 1024 = 4096 Sendevorgaenge! Das diese eine Weile dauern ist ganz normal!
Aber schauen wir uns mal deine Routine an!

 If pos = 0 Then
 pos = 1
 End If

Wieso das?

> wsckFile.GetData Data

Nicht gut!!! Gesetz dem Fall du sendest schneller als du empfängst so hast du streckenweise mehr wie die Blockgrösse an Daten! Es könnten bsp.weise mal 1512 Byte’s anliegen! Entweder du sendest ein Trennzeichen mit oder wenn du die Blockgrösse weisst dann kannst du auch die Daten einlesen. Aber woher soll der Client das wissen?
Soll die Routine nicht flexibel werden?

 intNewFile = FreeFile
'Das ist OK
 For i = 1 To BlocksCount
'Wo ist I Declariert?
'Selbst und wenn gesetz dem Falle Blocksize = 1024 und es liegen mal 
'1513 Bytes an. Du hast eine Schrittweite von 1 Aber 1512 / 1024 ist '1,477 ...
'Das bedeutet du würdest zwar die ersten 1024 Bytes schreiben, aber 'die restlichen verwerfen!

 Open strFile For Binary Access Write As #intNewFile
Das ist OK!

 Seek #intNewFile, pos

Ok, umstaendlich, aber Ok!


 Put #intNewFile, , Left(Data, Block)

Was ist wenn Data \> Block ist. Dann verwirfst du die Daten!

 Put #intNewFile, , Left(Data, Block)

Ja ok, das passt


> Close #intNewFile


Das auch, aber warum jedesmal die Datei öffnen und schliessen?

 pos = pos + Block
Auch das kann man einfacher machen :s

 If Len(Data) \> Block then
 Data = Mid(Data, Block + 1)
 End if

Hier hast du den naechsten Bock drinnen!
Nehmen wir mal an du bekommst 1027 Bytes gesendet!
Die letzten 3 byte sind ABC.
Hier würdest du unter DATA ABC speichern.
Nun kommen aber die naechsten 1513 Bytes an.
Durch die Anweisung "wsckFile.GetData Data" verwirfst du den Inhalt von Data. Sprich das ABC und die Daten sind verloren!
 Next i
Ja ok, das passt

Desweiteren prüfst du nicht ob genuegend Speicherplatz vorhanden ist.
OB das File schon existiert
Ob eine Verbindung zwischen den beiden Rechner besteht. Das sollte man vor JEDEM senden prüfen!

und und und.

Wie du nun siehst ist deine Routine sehr störanfaellig und fehlerhaft.
Du solltest dir dein Konzept nochmals ueberlegen.

Ein kleiner Tipp, um dein Ziel naeher zu kommen!

'Server
Vor jedem senden prüfen ob eine Verbindung besteht!
Beim senden.
Senden im Format [000000]DeineDaten
'Für die 0 setzt du von Rechts her die grösse der Daten ein die du sendest. Das hat den Vorteil das du flexibel bist!
'Du weisst das die ersten 8 Zeichen unrelevant sind.
'Bsp [000005]Start
Vor dem ersten senden, sendest du dem Clienten das es sich um ein Filehandling handelt.
'Dann sendest du die FileSize, danach den Filenamen und dann das der Transfer beginnt. Du kannst das natuerlich auch in eins senden. 
'Bsp:[000025]C:\Test.txt;412345676354 
'Dein Client weiss nun den Dateinamen und die Datenmenge!Anhand des ; kannst du die Daten trennen.
' Nach senden der Daten, lässt du den Server auf eine Bestaetigung 
'vom Clienten warten und danach sendest du die Daten in einer 
'Schleife in der Form [000000]Deine Daten
'Nach jeden Senden wartest du auf eine Bestaetigung!
'Nachdem alle Daten gesendet sind, sagst du das dem Clienten in der Form
'[000003]End
'Warten auf Bestatigung und schliessen des Connectes vom Clienten

'Client

'Beim Empfang, prüfen ob die Datei existiert: Je nachdem agieren
'FileSize und Dateinamen ermitteln
'Speicherplatz überprüfen
'Variable als Zeichenfolge declarieren und als STATIC 
'Server eine Bestaetigung senden
'Wenn Datenempfang kommt, Dann die Daten in einer zweiten Variable die auch als Static declariert ist speichern. Überprüfen ob die Anzahl der Zeichen stimmen! Wenn die Daten 

Das ist nur ein Weg von vielen und soll dir als Anstoss dienen. Das zu relaisieren ist rel. simple :smile:

MfG Alex


> Vielen Dank im Vorraus.  
>   
> MfG Hendrik Hilleckes

Hey,

vielen Dank für die lange Antwort, aber ich fürchte du hast
dir da etwas zuviel Arbeit gemacht.

Viele Dinge die du ansprichst habe ich bereits eingebaut,
aber die sind halt unerheblich für das Problem gewesen und daher nicht von mir gepostet worden.

Natürlich kontrolliere ich ob eine Verbindung besteht, ob Speicherplatz vorhanden ist oder ob die Datei bereits existiert.

Inzwischen funktioniert alles prächtig.
Dummerweise kann ich nicht genau sagen, woran es lag.
Ein Fehler war das ich an einer Stelle anstatt „FileLen“ nur „Len“ geschrieben hatte. Das konnte natürlich nicht den richtigen Wert liefern.

Trotzdem danke für die Antwort.
MfG Hendrik Hilleckes