Seite 1 von 2

Netzwerkdaten kommen nicht in einem Stück an

Verfasst: 06.06.2008 15:44
von dreamtec
Hi,

ich hab ein kleines Problem, was das senden von größeren Daten über Netzwerk angeht.
Ich habe ein String, das z.B. eine länge von 100.000 Zeichen hat. Schicke ich diesen mit dem sendNetworkString-Befehl, kommt nicht alles in einem stück an, obwohl auf der gegenseite der Buffer groß genug gewählt wurde ( 10.000.000 ).

Wenn ich WLan nutze, ist das noch extremer als mit Lan (Laufen client und server auf dem selben Rechner, funktioniert es erwartungsgemäß einwandfrei).

Woran kann sowas liegen?


Hier mal ein kleines beispiel, wie ich das meine

Code: Alles auswählen

;Server

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6832
*Buffer = AllocateMemory(10000000)

If CreateNetworkServer(0, Port)

  Repeat
    
    SEvent = NetworkServerEvent()
  Delay(1)
  
    If SEvent
    
      ClientID = EventClient()
  
      Select SEvent

        Case 2
          
            ReceiveNetworkData(ClientID, *Buffer, 1000000)
            MessageRequester("Info", "Empfangene Zeichen: "+Str(Len(PeekS(*Buffer))))
            
        Case 4
          quit = 1
      EndSelect
    EndIf
    
  Until Quit = 1 
  
  CloseNetworkServer(0)
Else
  MessageRequester("Error", "Can't create the server (port in use ?).", 0)
EndIf

  
End   

Code: Alles auswählen

;Client

If InitNetwork() = 0
  MessageRequester("Error", "Can't initialize the network !", 0)
  End
EndIf

Port = 6832

str.s = ""

For i.l = 0 To 999
  str = str + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"
Next

ConnectionID = OpenNetworkConnection("192.168.0.1", Port)
If ConnectionID
  SendNetworkString(ConnectionID, str)
  CloseNetworkConnection(ConnectionID)
Else
  MessageRequester("PureBasic - Client", "Can't find the server (Is it launched ?).", 0)
EndIf
  
End   

Verfasst: 06.06.2008 15:57
von STARGÅTE
es wäre besser den Buffer nicht so riesig zu wählen:
Statt:

Code: Alles auswählen

ReceiveNetworkData(ClientID, *Buffer, 1000000)
mal bitte mit

Code: Alles auswählen

TempBuffer=0
While ReceiveNetworkData(ClientID, *Buffer+TempBuffer, 4096) = 4096
 TempBuffer + 4096
Wend
testen

Verfasst: 06.06.2008 16:29
von dreamtec
Das hatte ich auch schonmal getestet. Leider besteht mit diesem Lösungsvorschlag immer noch das Problem. Zurzeit werden daraus immer 2 Pakete.

Verfasst: 06.06.2008 18:23
von HeX0R
Es werden immer mehrere Pakete werden, das ist schliesslich die Grundidee von TCP/IP.
Du musst dir schon ein wenig mehr Gedanken mit der Übertragung machen, z.B. ein gescheites Protokoll benutzen.

Ausserdem ist es denkbar schlecht den Rückkabewert von ReceiveNetworkData() einfach zu vernachlässigen.

Verfasst: 06.06.2008 22:42
von dreamtec
Wie TCP/IP funktioniert, weiss ich ja. Ich bin nur davon ausgegangen, dass das Ganze ähnlich wie bei C++ funktioniert.
Wenn ich mich richtig errinnere, macht dort ReceiveNetwork erst weiter, wenn der Stream unterbrochen wird (ich glaub der macht dort auch weiter, wenn der Buffer voll ist).

Naja, wenn es nicht anders funktioniert, muss ich mir halt was anderes überlegen.
Aber danke für eure Antworten. Jetzt weiss ich zumindest woran das liegt.

Verfasst: 06.06.2008 23:42
von ZeHa
Also so sehe ich das auch... egal was TCP/IP draus macht, das OS muß darüber eigentlich gescheit abstrahieren, sodaß es für den Programmierer so aussieht, als käme alles auf einmal. Schließlich muß so 'ne API ja mit jedem beliebigen Protokoll funktionieren. Daß TCP/IP aufteilt ist ein Implementationsdetail, das sollte normalerweise nicht der Programmierer selbst in der Hand haben müssen.

Verfasst: 07.06.2008 10:02
von dreamtec
gibt es eine möglichkeit, einen flush zu machen?

also ich hab aus

Code: Alles auswählen

SendNetworkString(ConnectionID, str)
das gemacht

Code: Alles auswählen

  While (Len(str) > 0)
    tmp.s = Mid (str, 1, 9)
    str = Mid (str, 11)
    SendNetworkString(ConnectionID, tmp)
    Delay(20)
  Wend
Das Problem ist nun, dass durch das schnelle versenden der Daten, mehrere Nachrichten wieder in einem Packet verschickt werden, und er selber die Daten irgendwo unterteilt. Und das will ich verhindern.

Verfasst: 07.06.2008 13:43
von freak
ZeHa hat geschrieben:Also so sehe ich das auch... egal was TCP/IP draus macht, das OS muß darüber eigentlich gescheit abstrahieren, sodaß es für den Programmierer so aussieht, als käme alles auf einmal. Schließlich muß so 'ne API ja mit jedem beliebigen Protokoll funktionieren. Daß TCP/IP aufteilt ist ein Implementationsdetail, das sollte normalerweise nicht der Programmierer selbst in der Hand haben müssen.
TCP/IP erzeugt einen Stream von Daten. Das heist alles kommt in der korrekten Reihenfolge an, aber nicht genau in den Mengen wie gesendet wurde.ReceiveNetworkData() gibt immer das zurück was momentan verfügbar ist, egal ob das nur der Teil eines SendNetworkData() war oder 100 auf einmal.

Man muss einfach einen kleinen header mitsenden der dem Empfänger sagt wieviele Daten er zu erwarten hat, dann kann der genausoviel lesen und hat dann die gleiche Datenmenge die gesendet wurde.

Verfasst: 07.06.2008 17:24
von PMV
STARGÅTE hat geschrieben:es wäre besser den Buffer nicht so riesig zu wählen:
Statt:

Code: Alles auswählen

ReceiveNetworkData(ClientID, *Buffer, 1000000)
mal bitte mit

Code: Alles auswählen

TempBuffer=0
While ReceiveNetworkData(ClientID, *Buffer+TempBuffer, 4096) = 4096
 TempBuffer + 4096
Wend
testen
sehr unsauber ... was ist, wenn nun nur 4095 Bytes empfangen wurden?
:wink:
dreamtec hat geschrieben:Das Problem ist nun, dass durch das schnelle versenden der Daten, mehrere Nachrichten wieder in einem Packet verschickt werden, und er selber die Daten irgendwo unterteilt. Und das will ich verhindern.
Das ist kein Problem, sondern gut ... so können die Daten viel
schneller versendet werden. Du musst dir ein kleines "Protokoll" überlegen,
in welchem du definierst, wie du deine Daten sendest. Wenn du z.b. immer
einen String von 9 Zeichen sendest, brauchst du auf der Empfängerseite
auch nur jeweils 9 Zeichen empfangen. Im Ascii-Modus wären das 9 Byte,
im Unicode-Modus 18 Byte. Es muss aber immer der Rückgabewert von
ReceiveNetworkData() überprüft werden ... es können zu jeder Zeit auch
mal nicht so viele Zeichen ankommen, wie man es gerne hätte.

MFG PMV

Verfasst: 08.06.2008 00:04
von dreamtec
Erstmal danke für eure erklärungen und lösungsvorschläge.
Du musst dir ein kleines "Protokoll" überlegen,
in welchem du definierst, wie du deine Daten sendest. Wenn du z.b. immer
einen String von 9 Zeichen sendest, brauchst du auf der Empfängerseite
auch nur jeweils 9 Zeichen empfangen. Im Ascii-Modus wären das 9 Byte,
im Unicode-Modus 18 Byte
Das hatte ich mir auch am Anfang gedacht. Nur habe ich leider keine feste größe.
Ich hab das jetzt so gelöst, dass die ersten 10 Bytes immer die länge des Strings sind. Anschließend überprüfe ich einfach, wieviele Zeichen ich empfangen habe. Sollte das nicht der mitgesendeten größe entsprechen, empfange ich erstmal weiter, bis alle Daten angekommen sind. Erst dann beginne ich mit der verarbeitung der Daten.