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:
- Erstmal ALLE eingehenden Daten an einen Buffer (präziser: einer FIFO Datenstruktur) hinten anhängen
- 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
Send 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
Send dann einfach blockiert, bis im Empfangsbuffer wieder Platz ist und alle Daten gesendet werden konnten.