noch ein daten senden problem

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Ah, der Fehler liegt im SendDataString:

Code: Alles auswählen

  stringsize.l=Len(string$)
  *mem=AllocateMemory(stringsize+1) ; hier bitte die +1 ergänzen
  PokeS(*mem, string$)
Das ist leider einer Fehler den ich auch gerne mache.
PokeS() schreibt die Zeichenkettenlänge + 1 Byte als NULL, daher musst du bei AllocateMemory die größe um eins erhöhen, damit es nicht zum Speicher-Überlauf kommt (kannst du mit dem Purifier erkennen (Kompileroptionen))

Das gilt dann auch beim empfangen dort bitte auch 1 Byte mehr reservieren.

PS: Von Unicode wollen wir jetzt mal absehen!
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 »

ah okay :) ja jetzt funktioniert ;)

aber jetzt hab ich noch eine kleine nuss die ihr für mich knacken müsst :/
und zwar war das ja nur ein beispiel code von mir am anfang.. jetzt hab ich das in mein hauptcode übertragen und siehe da.. er empfängt die strings nicht...
hab jetzt mal das ganze erkennungs und verarbeitungssystem in mein beispielcode eingebaut damit ihr euch das ma anschauen könnt..

Code: Alles auswählen

;Server

Procedure.s ReceiveDataString(ClientID)
   Protected ReceivedLength.i, string$, result, counter, stringsize.l, *mem
   result=ReceiveNetworkData(ClientID, @stringsize, 4)
   If result=4
      *mem=AllocateMemory(stringsize+1)
      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

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
      ReceiveNetworkData(EventClient(), @eins, 4)
      If  eins=1
        ReceiveNetworkData(EventClient(), @zwei, 4)
        If  zwei=2
          ReceiveNetworkData(EventClient(), @drei, 4)
          string$=ReceiveDataString(EventClient())
          PrintN(string$)
          string$=ReceiveDataString(EventClient())
          PrintN(string$)
        EndIf
      EndIf
    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+1)
  PokeS(*mem, string$)
  If  SendNetworkData(ClientID, @stringsize, 4)=4
    SendNetworkData(ClientID, *mem, stringsize)
  EndIf
  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)
eins=1
zwei=2
drei=3
SendNetworkData(verbindung, @eins, 4)
SendNetworkData(verbindung, @zwei, 4)
SendNetworkData(verbindung, @drei, 4)
SendDataString(verbindung, "teststring")
SendDataString(verbindung, "teststringzwei")
Repeat
  Delay(20)
  keypressed$=Inkey()
Until keypressed$=Chr(27)
End
also der sendet ja vorher nur long's um zu wissen wie er vorgehen muss..mehr macht er ja net.. :(

EDIT: also wenn man localhost eingibt, dann funktionierts..
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

keiner ne idee? :(
Sirius-2337
Beiträge: 71
Registriert: 29.05.2010 20:55

Re: noch ein daten senden problem

Beitrag von Sirius-2337 »

Wenn die Daten nicht schnell genug ankommen schreibst du die Daten immer wieder in 'eins'.
'zwei' und 'drei' werden nie mit Daten gefüllt und deswegen gehts auch nicht weiter.

Hier ein fuktionierender Code

Code: Alles auswählen

;Server

Procedure.s ReceiveDataString(ClientID)
   Protected ReceivedLength.i, string$, result, counter, stringsize.l, *mem
   result=ReceiveNetworkData(ClientID, @stringsize, 4)
   If result=4
      *mem=AllocateMemory(stringsize+1)
      counter=ElapsedMilliseconds() + 5000 ;*
      Repeat
         counter+1
         Delay(1)
         result=ReceiveNetworkData(ClientID, *mem+ReceivedLength, stringsize-ReceivedLength)
         If result > 0
            ReceivedLength + result
         EndIf
      Until ReceivedLength = stringsize Or counter<ElapsedMilliseconds() ;*
      string$ = PeekS(*mem)
      FreeMemory(*mem)
   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
      If eins = 0 ;*
        ReceiveNetworkData(EventClient(), @eins, 4)
      EndIf ;*
      If  eins=1
        If zwei = 0 ;*
          ReceiveNetworkData(EventClient(), @zwei, 4)
        EndIf ;*
        If  zwei=2
          If drei = 0 ;*
            ReceiveNetworkData(EventClient(), @drei, 4)
          EndIf ;*
          string$=ReceiveDataString(EventClient())
          PrintN(string$)
          string$=ReceiveDataString(EventClient())
          PrintN(string$)
          eins = 0 ;*
          zwei = 0 ;*
          drei = 0 ;*
        EndIf
      EndIf
    Case  #PB_NetworkEvent_Disconnect
      PrintN("Client nicht mehr verbunden")
  EndSelect
Until keypressed$=Chr(27)
End
Die von mir hinzugefügten Zeilen hab ich mit ";*" gekennzeichnet.
Benutzeravatar
Sicro
Beiträge: 964
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von Sicro »

Problem ist einfach, dass er nicht den Rückgabewert von ReceiveNetworkData berücksichtigt, wie ich schon mehrfach darauf hingewiesen habe.

Code: Alles auswählen

Case  #PB_NetworkEvent_Data
      If eins = 0 ;*
        ReceiveNetworkData(EventClient(), @eins, 4)
      EndIf ;*
Wenn im Empfangsbuffer noch keine 4 Bytes vorhanden sind, sondern z.B. nur 2 Bytes, werden 2 Bytes in die Long-Variable gespeichert und die If-Bedingung schlägt fehl, weil das Long noch nicht vollständig ist (Long = 4 Bytes) und der Wert somit nicht die gewünschte "1" entspricht.
In dem Fall wird die If-Bedingung nach dem nächsten Datenempfang wieder ausgeführt und versucht wieder 4 Bytes aus dem Empfangsbuffer auszulesen. Wir haben diesmal Glück - 4 Bytes sind vorhanden und werden ausgelesen. Der Long-Wert den wir erhalten ist jedoch ein anderer als den wir gesendet haben. Warum? Beim ersten Mal als wir den Empfangsbuffer ausgelesen haben, erhielten wir nur 2 Bytes. Diese haben wir nicht zwischengespeichert und sind somit verloren gegangen. Beim zweiten Mal haben wir also die letzten 2 Bytes des eins-Longs und die ersten 2 Bytes des zwei-Longs aus dem Empfangsbuffer geholt.

Kleine Veranschaulichung:

[xx][xx] entsprechen den zwei Words (2 Bytes) der Long (4 Bytes)

1. Senden: [11][22] = eins-Long
2. Senden: [33][44] = zwei-Long

1. Empfangen: eins-Long = [11] => Es waren leider nur 2 Bytes der 4 Bytes im Empfangsbuffer
2. Empfangen: eins-Long = [22][33] => Diesmal sind 4 Bytes im Empfangsbuffer

Normalerweise sollte eins-Long ja [11][22] sein. Es kamen aber nur 2 Bytes des eins-Longs beim ersten Empfang an. Diese wurden aber nicht zwischengespeichert und gingen verloren, somit haben sich die ganzen Daten verschoben und können den Longs nicht mehr richtig zugeordnet werden.

Vielleicht ist es nun klarer.
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
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

ah okay verstehe eigentlich soweit.. nur das is ja dann richtig doof gemacht bzw man muss sich da erstma richtig rein denken um nur so einen einfachen code zu schreiben...

also ich hab jetzt einfach mal so gemacht:

Repeat
result=ReceiveNetworkData(bla, bla, 4)
Until result=4

so funktiionierts zwar auch aber is wahrscheinlich nich 100%ig in ordnung nicht wahr?
Benutzeravatar
Sicro
Beiträge: 964
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von Sicro »

Moxl hat geschrieben:Repeat
result=ReceiveNetworkData(bla, bla, 4)
Until result=4

so funktiionierts zwar auch aber is wahrscheinlich nich 100%ig in ordnung nicht wahr?
Nein, auch nicht korrekt.

So könnten die Rückgaben sein:

result=ReceiveNetworkData(bla, bla, 4); result=3
result=ReceiveNetworkData(bla, bla, 4); result=1 ; Long vollständig empfangen (4 Bytes)
result=ReceiveNetworkData(bla, bla, 4); result=4 ; Repeat-Schleife wird verlassen, aber wir haben nun schon den zweiten Long empfangen

Mal ein Beispiel mit Strings:

1. Senden: "Das ist ein String"
2. Senden: "und das auch"

1. Empfang: "Das i"
2. Empfang: "st e"
3. Empfang: "in String und"
4. Empfang: " das auc"
5. Empfang: "h"

Um den vollständigen String zu empfangen, musst du die Daten von 1. bis 5. Empfang zusammenfügen. Dazu musst du aber die Daten von 1. bis 4. Empfang zwischenspeichern, sonst sind die Daten weg. Einmal aus dem Empfangsbuffer genommene Daten sind nicht mehr im Empfangsbuffer vorhanden.
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
Moxl
Beiträge: 150
Registriert: 26.10.2012 13:19

Re: noch ein daten senden problem

Beitrag von Moxl »

jo das verstehe ich ja soweit^^ und mit den strings da hab ich ja schon ne lösung gefunden.. jetzt fehlt halt noch die lösung wie genau ich das schreibe mit den long's
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: noch ein daten senden problem

Beitrag von STARGÅTE »

Obwohl ich eigentlich keine Lust hatte was zu coden, hier mal meine Idee für eine "sichere" (nicht Threadsicher) Version für das Senden von Zeichenketten (Ascii und Unicode, gesendet wird in UTF8) im Netzwerk.
Dabei sendet SendString() eine Zeichenkette und gibt bei Erfolg die Länge zurück.
ReceiveString() empfängt einen String, und achtet dabei auf die richtigen Zusammenhänge.
ReceiveString() gibt solange nichts zurück, solange der String noch nicht vollständig ist.
Auch gibt ReceiveString() immer nur ein String zurück, wenn im Puffer mehr sind, muss es mehrmals aufgerufen werden, bzw. über NetworkServerEvent() geprüft werden, ob noch Daten da sind.

Code: Alles auswählen

EnableExplicit

Structure ReceiveNetworkBlock
	Length.l
	Shift.i
	*Memory
	CurrentLength.i
EndStructure

Procedure.i SendString(ConnectionID.i, String.s)
	
	Protected Length.i = StringByteLength(String, #PB_UTF8)
	Protected CurrentLength.i, Result.i
	Protected *Buffer = AllocateMemory(SizeOf(Long)+Length+1)
	
	PokeL(*Buffer, Length)
	PokeS(*Buffer+SizeOf(Long), String, Length, #PB_UTF8)
	Repeat
		Result = SendNetworkData(ConnectionID, *Buffer, SizeOf(Long)+Length-CurrentLength)
		If Result > 0
			CurrentLength + Result
		ElseIf Result = -1
			FreeMemory(*Buffer)
			ProcedureReturn #False
		EndIf
	Until CurrentLength = SizeOf(Long)+Length
	FreeMemory(*Buffer)
	
	ProcedureReturn Length
	
EndProcedure

Procedure.s ReceiveString(ConnectionID.i)
	
	Static NewMap Connection.ReceiveNetworkBlock()
	Protected *Connection.ReceiveNetworkBlock, String.s
	Protected Key.s = Str(ConnectionID)
	Protected ReceiveLength.i, Length.i
	
	; Verbindungs suchen
	If FindMapElement(Connection(), Key)
		*Connection = Connection()
	Else
		*Connection = AddMapElement(Connection(), Key)
	EndIf
	If *Connection\Memory = #Null
		; Länge eines neuen Strings empfangen
		ReceiveLength = ReceiveNetworkData(ConnectionID, @*Connection\Length+*Connection\Shift, SizeOf(Long)-*Connection\Shift)
		If ReceiveLength > 0
			If ReceiveLength+*Connection\Shift = SizeOf(Long)
				*Connection\Memory = AllocateMemory(*Connection\Length+1)
			Else
				*Connection\Shift + ReceiveLength
			EndIf
		EndIf
	Else 
		; alten Strings weiter empfangen
		Length = *Connection\Length - *Connection\CurrentLength
		ReceiveLength = ReceiveNetworkData(ConnectionID, *Connection\Memory+*Connection\CurrentLength, Length)
		If ReceiveLength = Length
			String = PeekS(*Connection\Memory, *Connection\Length, #PB_UTF8)
			FreeMemory(*Connection\Memory)
			DeleteMapElement(Connection(), Key)
		ElseIf ReceiveLength > 0
			*Connection\CurrentLength + ReceiveLength
		EndIf 
	EndIf
	
	ProcedureReturn String
	
EndProcedure


InitNetwork()

CreateNetworkServer(1, 7000)
Define CID = OpenNetworkConnection("84.189.151.203", 7000)
Define String.s

Debug SendString(CID, "Hallo Welt!")
Debug SendString(CID, "Das ist eine andere Zeichenkette.")
Debug SendString(CID, "Hier kommt noch was langes: "+Space(4000)+" das wars.")
Debug SendString(CID, "Ende!")

Repeat
   If NetworkServerEvent() = #PB_NetworkEvent_Data
      String = ReceiveString(EventClient())
      If String : Debug Str(Len(String))+" : "+String : EndIf
   Else
      Delay(1)
   EndIf
ForEver

Vielleicht haben ja die anderen Fachkundigen hier noch Verbesserungsvorschläge.
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 das ist doch genau das was ich wollte :)
jetzt brauch ich das selbe nur noch mit long's dann bin ich glücklich :D
Antworten