TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Für allgemeine Fragen zur Programmierung mit PureBasic.
Beefi
Beiträge: 96
Registriert: 16.01.2017 17:38

TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von Beefi »

Hi Leute,

so, ein Problem gelöst und gleich das nächste Problem am Start :mrgreen:
Bei mir gibt es ein Problem beim Datenempfang über TCP/IPv4...vielleicht hat jemand einen goldenen Tipp für mich...

Ich sende über TCP ein Bild...die Prozedur auf dem Server sieht so aus (ist ein leicht veränderter Schnipsel hier aus dem Forum):

Code: Alles auswählen

Procedure.l Server_SendImage(lImage.l)
  
  Define *ImageMemory = EncodeImage(lImage, #PB_ImagePlugin_PNG)
  
 
  ForEach List_Clients()
  
    Protected sent.i, sentTotal.i = 0
    While Not sentTotal = MemorySize(*ImageMemory)
    
      sent = SendNetworkData(List_Clients(), *ImageMemory + sentTotal, MemorySize(*ImageMemory) - sentTotal)
      
      If sent = -1 : ProcedureReturn #False : EndIf
      
      sentTotal + sent
    Wend
    
  Next
  
  FreeMemory(*ImageMemory)
  ProcedureReturn #True
EndProcedure
Das funzt, und sollte keine Probleme machen. Also das Image wird per EncodeImage() in einen "Memory-Block" geschrieben und dieser Speicherbereich wird dann versendet...wenn es nicht mit einer "Ladung" klappt (weil Datenmenge zu groß), gibts halt noch weitere Pakete.


Auf dem Client wird das Bild mit diesen Anweisungen empfangen (als Thread laufend):

Code: Alles auswählen

Procedure NetClient_Update(*Value)
  
  Repeat
    If Thread_NetClient_ShouldStop : ProcedureReturn : EndIf
    
    Define ClientEvent.l = NetworkClientEvent(lNetConnection)
    If ClientEvent
      Select ClientEvent
      
        Case #PB_NetworkEvent_Data
        
          Protected *Buffer = AllocateMemory(65000)
          Protected *ReceivedPacket = #Null
          Protected ReceivedLen.q
          Protected AppendAddress.i
          
          Repeat
            ReceivedLen = ReceiveNetworkData(lNetConnection, *Buffer, MemorySize(*Buffer))
            *ReceivedPacket = ReAllocateMemory(*ReceivedPacket, ReceivedLen)
            AppendAddress = MemorySize(*ReceivedPacket) - ReceivedLen
            CopyMemory(*Buffer, *ReceivedPacket + AppendAddress , ReceivedLen)
            
            If ReceivedLen < MemorySize(*Buffer)
              Break
            EndIf
          ForEver
          
          Define ReceivedImage.l = CatchImage(#PB_Any, *ReceivedPacket)
          VisuUpdate(ReceivedImage)

          
        Case #PB_NetworkEvent_Disconnect
          ProcedureReturn

      EndSelect
    EndIf
  ForEver

EndProcedure

Nun ist es so, dass die Purebasic-eigene Prozedur CatchImage() nicht immer ein gültiges Image zurück gibt. Also würde ich auf die Variable "ReceivedImage" ein IsImage() ansetzen, so kommt nur selten ein #True heraus. Meistens nach dem Start des Programms, dann gar nicht mehr. Manchmal kommt es auch zu einem Fehler wegen falschen Speicheradressenzugriff (falls ich es im Debugger starte).
Das komische ist jedoch...während der Entwicklungszeit (auf dem gleichen Rechner, mit Localhost 127.0.0.1) lief es perfekt...egal wie lange man das ganze laufen lies...Bild für Bild wurde perfekt übertragen.
Jetzt im Einsatz über ein reales LAN und zwei PC's, gibts plötzlich diese Probleme.
Hat jemand einen Tipp, woran es liegen könnte, oder wo ich vielleicht eine Gurke reinprogrammiert habe?

Wer sich wundert, was das mit AppendAddress und CopyMemory() soll...falls die übertragenen Daten zu groß sind und über mehrere Pakete verteilt werden, müssen diese ja wieder in der richtigen Reihenfolge zusammengesetzt werden. Das war so meine Idee zur Lösung...vielleicht gehts ja auch simpler :mrgreen:
Benutzeravatar
jacdelad
Beiträge: 404
Registriert: 03.02.2021 13:39
Wohnort: Riesa
Kontaktdaten:

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von jacdelad »

Die Frage kommt immer wieder auf. Es gibt im englischen Forum ein oder zwei Module, die speziell für die Übertragung von Datenmengen größer 64kB ausgelegt sind. Schau mal dort.
Guten Morgen, das ist ein schöner Tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3 TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von mk-soft »

Um mit Netzwerk zu arbeiten gehört auch das einarbeiten in die Netzwerk Protokolle und wie dieses funktioniert.
Daten werden über Netzwerk als Pakete übertragen. Bei TCP/IP musst du dich selber darum kümmern das die Daten vollständig sind. Zum Beispiel mit eigenen Header mit Längenangaben.
Auf jedem fall mal in Wikipedia nach TCP/IP suchen und nachlesen.

Hier auch ein Module von mir um größere Daten zu übertragen.
Link: Module NetworkTCP
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benubi
Beiträge: 187
Registriert: 22.10.2004 17:51
Wohnort: Berlin, Wedding

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von Benubi »

Da gibt's aber eine Menge aufzuräumen :)

Code: Alles auswählen

If sent = -1 : ProcedureReturn #False : EndIf
Hier brichst Du die Übertragung ab, obwohl der Client noch verbunden ist - es ist lediglich der Ausgangs-Puffer voll. Ich würde folgendes vorschlagen:

Code: Alles auswählen

If sent =-1 : Delay(0) : ElseIf sent = 0 : ProcedureReturn #False : EndIf
Hierbei bleibt der Server aber beschäftigt bis das Bild vollständig übertragen wurden. Möglicherweise kann man hier aber auch einen Thread benutzen, aber bevor das passiert sollten die Defines durch Protected oder Threaded ersetzt werden, bzw. außerhalb der Prozeduren stehen.

Die Handles sollten alle vom Integer .i Datentyp sein, nicht in Long .l, wenn das Programm auf 64 Bit Systemen laufen können soll.

Auch fehlt bei dem Algorithmus eine Kontrolle über die gesendete Bildgröße, daher sollte vor jeder Bild-Übertragung ein kleiner Header vorangehen mit Dateilänge/Nachrichtenlänge und eventuell Nachrichten-Typ. Dann kann auf der Empfängerseite effizient gearbeitet werden. Ohne den Header fischst Du im Trüben und mußt Dich darauf verlassen, daß die gesammte Bilddatei exakt 65000 Bytes groß ist etc.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von NicTheQuick »

Bei TCP/IP musst du dich nicht darum kümmern, dass Daten in der richtigen Reihenfolge ankommen. Das macht das Protokoll schon für dich. Es kümmert sich außerdem darum, dass immer alle Daten ankommen und nichts fehlt.
Nur ein Timeout von standardmäßig 120 Sekunden (zumindest unter Linux) würde signalisieren, dass die Verbindung aus irgendwelchen Gründen verschwunden ist, z.B. Stecker gezogen, Firewall plötzlich abgedichtet, usw.
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von mk-soft »

Must trotzdem die Länge der Daten (des Bildes) als Header mit übertragen, sonst weiss du nicht wann alle Daten angekommen sind.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von NicTheQuick »

Klar, das muss man dennoch machen.
Beefi
Beiträge: 96
Registriert: 16.01.2017 17:38

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von Beefi »

Hi Leute,

vielen Dank für die Tips...ich habe es so nun hinbekommen. Wie schon oft von euch erwähnt...der Header machts aus :D

Da hatte ich mich zu sehr auf die Beschreibung in der Purebasic-Hilfe von ReceiveNetworkData() versteift:
Gibt die Anzahl an empfangenen Bytes zurück. Ist das 'Ergebnis' gleich der 'DatenPufferLänge', dann sind weitere Daten zum Einlesen verfügbar. Wenn ein Fehler bei der Verbindung auftrat (Verbindung unterbrochen, Verbindung durch den Server beendet, etc.), wird 'Ergebnis' gleich -1 sein.
Im Realbetrieb kamen mehrere Pakete mit unterschiedlichsten Größen rein...allesamt kleiner als die maximale Pufferlänge (was ja laut Beschreibung indirekt heißt -> Fertig mit der Übertragung).

Habe einen Speicherbereich adressiert, einen kleinen Header vorne dran gehängt und dann das Bild. Der Header besteht lediglich aus 11 bytes:
3 bytes für die Art "IMG"
und 8 bytes für ein Quad mit Angabe der Bildgröße

Das ganze auf der Gegenseite simpel ausgewertet und funzt absolut perfekt...Jedes CatchImage() ein Volltreffer :allright:
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von NicTheQuick »

Bei echten Netzwerken werden die Datenpakete an jedem Knotenpunkt, also Router, Switch und Co neu paketiert und können so eine ganz andere Größe haben. Stichwort MTU.
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: TCP-Daten werden auf Empfängerseite nicht korrekt empfangen/zusammengesetzt. Lösungsvorschlag gesucht.

Beitrag von mk-soft »

Mit SendNetworkData werden die Daten zum Sendebuffer übertragen. Das Ergebnis heisst nicht das die zu Daten gesendet oder angekommen sind.
Mit ReceiveNetworkData werden die Daten aus dem Empfangsbuffer abgeholt. Das heisst nicht das die Daten alle empfangen sind.
Diese werden auch nicht getrennt sein, wenn man mehrere Daten getrennt gesendet hat.
TCP/IP ist das Grundprotokoll welches die Daten überträgt. Auf diesen wird wieder die Anwenderschicht aufgesetzt welches sich um die Inhalte zu kümmern hat. Wie HTTP, HTTPS, FTP, MAIL, MODBUS/TCP, etc.

Daher mit eigenen Header arbeiten mit Längenangabe und mehr wie bei meinen Modul NetworkTCP
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten