noch ein daten senden problem

Anfängerfragen zum Programmieren mit PureBasic.
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

noch ein daten senden problem

Beitrag von Moxl »

Hallo an alle :)

ich hab vor strings mittels SendNetworkData() zu senden.
Jetzt sende ich ja erst die stringlänge und direkt danach den string und so rufe ich beim empfänger dann auch die daten ab...
also wenn daten zum abrufen verfügbar sind dann empfängt er erst die stringlänge und direkt danach empfängt der die daten des strings

hab das hier mal gebastelt

Code: Alles auswählen

;Server

Procedure SendDataString(ClientID, string$)
  stringsize.l=Len(string$)
  *mem=AllocateMemory(stringsize)
  PokeS(*mem, string$)
  SendNetworkData(ClientID, @stringsize, 4)
  Debug "Server stringsize gesendet: "+Str(stringsize)
  SendNetworkData(ClientID, *mem, stringsize)
  FreeMemory(*mem)
EndProcedure
Procedure.s ReceiveDataString(ClientID)
  ReceiveNetworkData(ClientID, @stringsize, 4)
  Debug "Server stringsize empfangen: "+Str(stringsize)
  *mem=AllocateMemory(stringsize)
  ReceiveNetworkData(ClientID, *mem, stringsize)
  string$=PeekS(*mem)
  FreeMemory(*mem)
  ProcedureReturn string$
EndProcedure

OpenConsole()
If  InitNetwork()<>0
  PrintN("Netzwerk initialisiert")
Else
  End
EndIf
If  CreateNetworkServer(0, 6800)<>0
  PrintN("Server wurde gestartet")
Else
  End
EndIf
PrintN("")
Repeat
  Delay(20)
  keypressed$=Inkey()
  serverevent=NetworkServerEvent()
  Select  serverevent
    Case  #PB_NetworkEvent_Connect
      PrintN("Client verbunden")
    Case  #PB_NetworkEvent_Data
      string$=ReceiveDataString(EventClient())
      PrintN(string$)
    Case  #PB_NetworkEvent_Disconnect
      PrintN("Client nicht mehr verbunden")
  EndSelect
Until keypressed$=Chr(27)
End

Code: Alles auswählen

;Client

Procedure SendDataString(ClientID, string$)
  stringsize.l=Len(string$)
  *mem=AllocateMemory(stringsize)
  PokeS(*mem, string$)
  SendNetworkData(ClientID, @stringsize, 4)
  Debug "Client stringsize gesendet: "+Str(stringsize)
  SendNetworkData(ClientID, *mem, stringsize)
  FreeMemory(*mem)
EndProcedure
Procedure.s ReceiveDataString(ClientID)
  ReceiveNetworkData(ClientID, @stringsize, 4)
  Debug "Client stringsize empfangen: "+Str(stringsize)
  *mem=AllocateMemory(stringsize)
  ReceiveNetworkData(ClientID, *mem, stringsize)
  string$=PeekS(*mem)
  FreeMemory(*mem)
  ProcedureReturn string$
EndProcedure

OpenConsole()
If  InitNetwork()<>0
  PrintN("Netzwerk initialisiert")
Else
  End
EndIf
verbindung=OpenNetworkConnection("localhost", 6800)
If  verbindung<>0
  PrintN("Verbindung hergestellt")
Else
  End
EndIf
PrintN("")
Delay(3000)
SendDataString(verbindung, "teststring")
Repeat
  Delay(20)
  keypressed$=Inkey()
  clientevent=NetworkClientEvent(verbindung)
  Select  clientevent
    Case  #PB_NetworkEvent_Data
      string$=ReceiveDataString(EventClient())
      PrintN(string$)
  EndSelect
Until keypressed$=Chr(27)
End
mit "localhost" funktioniert auch alles wunderbar... aber wenn ich ne ip bzw ne dyndns eingebe, dann kommt beim debugger nur müll raus :/ erst empfängt der server 1 und danach immer ne andere 10-15 stellige zahl :?

woran liegt das?
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von Sicro »

Hallo Moxl,

du berücksichtigst wie viele nicht die Rückgabewerte von SendNetworkData bzw. ReceiveNetworkData. Die Befehle müssen so gut wie immer mehrfach aufgerufen werden, um alle Daten zu senden/empfangen.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Da ich auch keine Lust habe den Code zu korrigieren, hier nur ein paar Worte zum Verständnis:

SendNetworkData:
Die Funktion SendNetworkData() macht nichts anderes, als den übergebenen Speicherbereich in den Ausgangspuffer der Netzwerkkarte zu kopieren. Dabei werden mehre Puffer einfach hintereinander abgelegt, ohne Abgrenzung. Die eigentliche Übertragung verkläuft also nicht zwangsläuftig in den Puffergrößen, die bei SendNetworkData() angegeben sind.
Der Rückgabewert gibt keinerlei Aufschluss darüber ob, wann und wie viele Bytes tatsächlich übertragen wurden! Das einzige was u.u. zurückgegeben wird, ist ein Fehler wenn der Puffer voll ist.

ReceiveNetworkData:
Die Funktion ReceiveNetworkData() macht nichts anderes, als vorhandene Daten aus dem Netzwerk-Eingangspuffer in den übergebenen Speicher zu kopieren. Dabei wird zum Zeitpunkt des Aufrufs nur das Kopiert, was auch da ist, unabhängig davon ob die Übertragung schon fertig ist, oder noch was kommt. Dabei ist der Längenparameter nur eine Vorgabe.
Nur der Rückgabewert selbst gibt an, wie viel tatsächlich kopiert wurde.

Was ist also das Problem bei deinem Code:
SendDataString() ist erst mal soweit ok, auch wenn du nicht prüfts, ob SendNetworkData() ggf. fehlschlägt.
ReceiveDataString() ist dageben falsch. Beim zweiten ReceiveNetworkData() sollen zwar "stringsize"-Bytes gelesen werden, aber ob das wirklich der Fall war, überprüfst du nicht. Es kann durchaus sein, das die 4-Bytes für die länge bereits angekommen sind, der String selber aber noch unterwegs ist, dann würde beim 2. mal 0 zurückgegeben werden, sodass du warten musst. Da du das nicht gemacht hast, empfängt er danach immer wieder neue 4-Bytes als Länge, obwohl es vllt schon der String selbst ist. Hier müsstest du eine Schleife einbauen, die solange die restlichte Länge einließt, bis alles vom String da ist. Erst danach darfst du die Funktion verlassen.
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
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

ahhh eine wunderschöne beschreibung :) danke :)

ja du hast recht.. wenn ich eine schleife bei ReceiveNetworkData mache dann funktionierts :mrgreen:

is alles sehr gut nachvollziehbar :)

vielen dank :allright:
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Wäre nett, wenn du deinen korrigierten Code bitte noch mal postest, damit andere deine "Lösung" auch benutzen können, bzw. wir noch mal drüber gucken können.
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
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

okay also mein code sieht jetzt wie folgt aus... jetzt hab ich nur ein problem und zwar wenn ich zwei strings nach einander senden will... dann kommt beim zweiten string nich das raus was ich gesendet habe...

Code: Alles auswählen

;Server

Procedure.s ReceiveDataString(ClientID)
  result=ReceiveNetworkData(ClientID, @stringsize, 4)
  If  result=4
    *mem=AllocateMemory(stringsize)
    counter=0
    Repeat
      counter+1
      Delay(1)
      result=ReceiveNetworkData(ClientID, *mem, stringsize)
    Until result=stringsize Or counter>6000
    If  result=stringsize
      string$=PeekS(*mem)
      FreeMemory(*mem)
    EndIf
  EndIf
  ProcedureReturn string$
EndProcedure

OpenConsole()
If  InitNetwork()<>0
  PrintN("Netzwerk initialisiert")
Else
  End
EndIf
If  CreateNetworkServer(0, 6800)<>0
  PrintN("Server wurde gestartet")
Else
  End
EndIf
PrintN("")
Repeat
  Delay(20)
  keypressed$=Inkey()
  serverevent=NetworkServerEvent()
  Select  serverevent
    Case  #PB_NetworkEvent_Connect
      PrintN("Client verbunden")
    Case  #PB_NetworkEvent_Data
      string$=ReceiveDataString(EventClient())
      PrintN(string$)
    Case  #PB_NetworkEvent_Disconnect
      PrintN("Client nicht mehr verbunden")
  EndSelect
Until keypressed$=Chr(27)
End

Code: Alles auswählen

;Client

Procedure SendDataString(ClientID, string$)
  stringsize.l=Len(string$)
  *mem=AllocateMemory(stringsize)
  PokeS(*mem, string$)
  SendNetworkData(ClientID, @stringsize, 4)
  SendNetworkData(ClientID, *mem, stringsize)
  FreeMemory(*mem)
EndProcedure

OpenConsole()
If  InitNetwork()<>0
  PrintN("Netzwerk initialisiert")
Else
  End
EndIf
verbindung=OpenNetworkConnection("localhost", 6800)
If  verbindung<>0
  PrintN("Verbindung hergestellt")
Else
  End
EndIf
PrintN("")
Delay(3000)
SendDataString(verbindung, "teststring")
SendDataString(verbindung, "teststringnummerzwei")
Repeat
  Delay(20)
  keypressed$=Inkey()
Until keypressed$=Chr(27)
End
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Dein Code ist ja auch noch nicht richtig.
Natürlich musst du die Memory-Position anpassen (wenn du bereits ein teil bekommen hast) und dann auch die noch zu lesende Datenmenge.
Außerdem solltest du den reservierten Speicher IMMER freigeben, und nicht nur dann, wenn es erfolg hatte.

Auch wenn ich den Code noch nicht "schön" finde, sollte er nun funktionieren:

Code: Alles auswählen

Procedure.s ReceiveDataString(ClientID)
	Protected ReceivedLength.i, string$, result, counter, stringsize.l, *mem
	result=ReceiveNetworkData(ClientID, @stringsize, 4)
	If result=4
		*mem=AllocateMemory(stringsize)
		counter=0
		Repeat
			counter+1
			Delay(1)
			result=ReceiveNetworkData(ClientID, *mem+ReceivedLength, stringsize-ReceivedLength)
			If result > 0
				ReceivedLength + result
			EndIf
		Until ReceivedLength = stringsize Or counter>6000
		string$ = PeekS(*mem)
		FreeMemory(*mem)
	EndIf
	ProcedureReturn string$
EndProcedure
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
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von Sicro »

STARGÅTE hat geschrieben:SendNetworkData:
Der Rückgabewert gibt keinerlei Aufschluss darüber ob, wann und wie viele Bytes tatsächlich übertragen wurden!
Ob die Bytes tatsächlich schon übertragen wurden oder dann noch im Sendebuffer sind, weiß ich nicht, aber der Rückgabewert gibt sehr wohl die übertragene/kopierte Datenmenge zurück. Bei schlechten Verbindungen können bereits schon bei kurzen Strings (z.B. HTML-Request-Header) mehrere Aufrufe von SendNetworkData erforderlich sein.

Code: Alles auswählen

Procedure.s ReceiveDataString(ClientID)
  result=ReceiveNetworkData(ClientID, @stringsize, 4)
  If  result=4
[...]
Und wenn result nicht 4 (Bytes) ist?
Es kann sein, dass erst 2 Bytes empfangen wurden und die anderen 2 Bytes erst noch empfangen werden müssen. Die 2 Bytes die du nun in meinem Beispiel bereits ausgelesen hast, musst du zwischenspeichern (die sind ja nun nicht mehr im Emfangspuffer) und mit den noch folgenden 2 Bytes ergänzen, um das vollständige Long dann zu erhalten:

Code: Alles auswählen

*mem = AllocateMemory(4)
If *mem = 0
  Debug "Speicherbereich konnte nicht reserviert werden!"
  End
EndIf

time = ElapsedMilliseconds()
Repeat
  If NetworkServerEvent() = #PB_NetworkEvent_Data
    time = ElapsedMilliseconds()
    
    ReceivedDataSize = ReceiveNetworkData(EventClient(), *mem + AllReceivedDataSize, 4 - AllReceivedDataSize)
    If ReceivedDataSize > 0
      AllReceivedDataSize + ReceivedDataSize
    EndIf
    
    If AllReceivedDataSize = 4
      ; Wir haben den vollständigen Long !!!
      stringsize.l = PeekL(*mem)
      Break
    EndIf
  EndIf
  
  If (ElapsedMilliseconds() - time) >= 10000 ; 10 Sekunden TimeOut
    ; Die Übertragung dauert zu lange und wird abgebrochen
    Break
  EndIf
ForEver

FreeMemory(*mem)

Code: Alles auswählen

;Client
[...]
Rückgabewert von SendNetworkData wird nicht berücksichtigt.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6999
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Sicro hat geschrieben:Ob die Bytes tatsächlich schon übertragen wurden oder dann noch im Sendebuffer sind, weiß ich nicht, aber der Rückgabewert gibt sehr wohl die übertragene/kopierte Datenmenge zurück. Bei schlechten Verbindungen können bereits schon bei kurzen Strings (z.B. HTML-Request-Header) mehrere Aufrufe von SendNetworkData erforderlich sein.
Was du mit "schlechte" Verbindungs meinst weiß ich nicht. Aber fest steht, dass SendNetworkData auf jedenfall nicht wartet bis die Daten angekommen sind, sondern nur zurück gibt, ob das abschicken erfolgreich war.
Folgender Code gibt mir innerhalb einer Sekunde das Resultat von SendNetworkData zurück: 10485760 (alle 10MB) sind "verschickbar".
Danach kommen aber nur "kleckerweise" die Daten an (upload nur 14kB/s):
Hier benutze ich meine Internet-IP, damit die Daten wirklich verschickt werden.

Code: Alles auswählen

InitNetwork()

CreateNetworkServer(1, 7000)
CID = OpenNetworkConnection("84.189.***.***", 7000)

*Buffer = AllocateMemory(10*1024*1024)
RandomData(*Buffer, MemorySize(*Buffer))
Debug SendNetworkData(CID, *Buffer, MemorySize(*Buffer))

Repeat
	If NetworkServerEvent() = #PB_NetworkEvent_Data
		Debug ReceiveNetworkData(EventClient(), *Buffer, MemorySize(*Buffer))
	Else
		Delay(1)
	EndIf
ForEver
10485760
1452
1452
1452
1452
1452
1452
1452
1452
Sicro hat geschrieben:Und wenn result nicht 4 (Bytes) ist?Es kann sein, dass erst 2 Bytes empfangen wurden und die anderen 2 Bytes erst noch empfangen werden müssen. Die 2 Bytes die du nun in meinem Beispiel bereits ausgelesen hast, musst du zwischenspeichern (die sind ja nun nicht mehr im Emfangspuffer) und mit den noch folgenden 2 Bytes ergänzen, um das vollständige Long dann zu erhalten:
Das ist natürlich richtig, danke fürs Update. Hab selbst auch noch mal in meinem Include geguckt, und dort hab ich es auch drin.
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
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

gut okay hab jetzt nochmal den code von stargate ausprobiert aber leider funktioniert es immernoch nich :/
das mit dem überprüfen das wirklich alle 4 byte da sind das hab ich mir jetzt mal gespart weil die eigentlich immer ankommen :/
Antworten