Thema: Delphi Spielwiese - SocketTest

Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#28

AW: Spielwiese - SocketTest

  Alt 22. Dez 2016, 17:04
Hat jemand so pauschal eine Idee, wie das Problem Socket.ReceiveLength=0 zu lösen ist?
Der von dir verlinkte Code hat mehrere Schwächen:
  • Theoretisch ist es möglich, dass die Länge schon nicht in einem Stück ankommt
  • Wenn du zwei Streams hintereinander schickst, kann das letzte Paket von Stream 1 bereits die Länge und Daten von Stream 2 enthalten
Einfachste Vorgehensweise:
  1. Erstmal ALLE eingehenden Daten an einen Buffer (präziser: einer FIFO Datenstruktur) hinten anhängen
  2. Dann in einer Schleife alle vollständigen Pakete abarbeiten (Pseudo-Code):
    Delphi-Quellcode:
    while ((PacketSize = 0) and (BufferSize >= SizeOf(PacketSize)) or
      ((PacketSize > 0) and (BufferSize >= PacketSize)) do
    begin
      if (PacketSize = 0) then
      begin
        // Hier PacketSize vom Anfang des Buffers auslesen, dann alle Daten
        // im Buffer um SizeOf(PacketSize) nach vorne verschieben und schließlich
        // BufferSize um SizeOf(PacketSize) dekrementieren
      end;
      // Vollständiges Paket vorhanden
      if (BufferSize >= PacketSize) then
      begin
        // Hier Paket-Daten vom Anfang des Buffers auslesen, dann alle Daten
        // im Buffer um PacketSize nach vorne verschieben und schließlich
        // BufferSize um PacketSize dekrementieren
      end;
    end;
Durch diese Vorgehensweise solltest du alle Möglichen Fälle abdecken. Aus Performancegründen würde ich noch versuchen die Verschiebe- und besonders die Realloc Operationen des Buffers zu minimieren. Beispielsweise könntest du noch ein zustäzliches Feld BufferPos pflegen, mit dem du dir diese Aktionen sparst (müssten dann nur einmalig nach der Schleife ausgeführt werden, aber nicht bei jedem Durchlauf). Falls deine Pakete nicht in anderen Threads abgearbeitet werden, kannst du dir auch das Auslesen der Paketdaten sparen und deinem Paket-Handler einfach einen Zeiger auf @Buffer[BufferPos] zurückgeben, etc. Auch würde ich den Buffer nie komplett auf Null shrinken, sondern immer mindestens X-Byte alloziiert lassen, damit du bei kleineren Paketen im Optimalfall sogar komplett auf Realloc verzichten kannst.

Edit:
Achso und wie sieht deine Sende-Routine aus? Bei non-blocking Sockets kann MSDN-Library durchsuchenSend auch erfolgreich sein, aber trotzdem keine bzw. nicht alle Daten senden (wenn der Empfangsbuffer zu voll ist). Deshalb musst du hier in einer Schleife selbst dafür sorgen, dass alles verschickt wird. Bei den blocking Sockets kann das nicht passieren, da MSDN-Library durchsuchenSend dann einfach blockiert, bis im Empfangsbuffer wieder Platz ist und alle Daten gesendet werden konnten.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl (22. Dez 2016 um 17:08 Uhr)
  Mit Zitat antworten Zitat