Netzwerkdaten kommen nicht in einem Stück an

Anfängerfragen zum Programmieren mit PureBasic.
dreamtec
Beiträge: 13
Registriert: 06.06.2008 14:34

Netzwerkdaten kommen nicht in einem Stück an

Beitrag 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   
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag 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
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
dreamtec
Beiträge: 13
Registriert: 06.06.2008 14:34

Beitrag von dreamtec »

Das hatte ich auch schonmal getestet. Leider besteht mit diesem Lösungsvorschlag immer noch das Problem. Zurzeit werden daraus immer 2 Pakete.
Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Beitrag 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.
dreamtec
Beiträge: 13
Registriert: 06.06.2008 14:34

Beitrag 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.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag 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.
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
dreamtec
Beiträge: 13
Registriert: 06.06.2008 14:34

Beitrag 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.
freak
PureBasic Team
Beiträge: 766
Registriert: 29.08.2004 00:20
Wohnort: Stuttgart

Beitrag 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.
Benutzeravatar
PMV
Beiträge: 2765
Registriert: 29.08.2004 13:59
Wohnort: Baden-Württemberg

Beitrag 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
alte Projekte:
TSE, CWL, Chatsystem, GameMaker, AI-Game DLL, Fileparser, usw. -.-
dreamtec
Beiträge: 13
Registriert: 06.06.2008 14:34

Beitrag 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.
Antworten