AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Socket C&S

Ein Thema von tomkupitz · begonnen am 6. Feb 2018 · letzter Beitrag vom 9. Feb 2018
Antwort Antwort
Seite 1 von 3  1 23   
tomkupitz

Registriert seit: 26. Jan 2011
146 Beiträge
 
Delphi 10.3 Rio
 
#1

Socket C&S

  Alt 6. Feb 2018, 16:48
Hallo,

ich schicke mit

Code:
SendBuf(buf[0], Length(buf));
Daten an den Client. Dort kommen die Daten

Code:
Socket.ReceiveBuf(buf[0], Socket.ReceiveLength);
aber nicht in einem Stück an. Wie groß darf buf max. sein? Oder kann erzwingen das alles komlett empfangen werden kann?

Danke und beste Grüße
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.611 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: Socket C&S

  Alt 6. Feb 2018, 16:53
aber nicht in einem Stück an. Wie groß darf buf max. sein? Oder kann erzwingen das alles komlett empfangen werden kann?
Kurze und schmerzhafte Antwort: Nein, erzwingen kannst du leider nichts.

Du musst dir ein eigenes kleines Protokoll bauen. Einfachste Lösung wäre das Vorwegsenden eines Ints/Int64 mit der Länge der Daten.

Edit:
Auf Empfängerseite sind leider einige Dinge zu beachten. Z.b. kann es nicht nur passieren, dass die Pakete fragmentiert werden, sondern mehrere Pakete können auch "in einem Rutsch" ankommen. Auch kann es dir passieren, dass dein Int/Int64 nicht vollständig ist. Du benötigst also auf jeden Fall einen Zwischenspeicher (sowas wie eine Queue [FIFO] für zusammenhängende Daten) und musst Diesen dann in einer Schleife stückweise abarbeiten.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl ( 6. Feb 2018 um 17:01 Uhr)
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
462 Beiträge
 
Delphi 2009 Professional
 
#3

AW: Socket C&S

  Alt 6. Feb 2018, 19:40
MTU von Ethernet ist normalweise 1518 minus
  • Ethernet (18 Bytes), daher wird die MTU meist mit 1500 angegeben
  • Internet Protocol (v4: meist 20 Bytes; v6: 40 Bytes)
  • Transport (UDP: 8 Bytes; TCP: 20 Bytes)
Darauf verlassen kann man sich wie Zacherl schon sagte aber nicht, da der Nutzer das einstellen kann.
Indy macht aber auch manchmal Blödsinn. Ich habe auch schon mal das Problem gehabt, dass bestimmte Indy-Methoden das erste Byte einzeln geschickt haben.
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
tomkupitz

Registriert seit: 26. Jan 2011
146 Beiträge
 
Delphi 10.3 Rio
 
#4

AW: Socket C&S

  Alt 6. Feb 2018, 20:15
Hallo,

wenn die Daten blockweise eintreffen sollte ReceiveLength die jeweilige Blockgröße angeben. Wie ich aber lese ist der Wert von ReceiveLength nicht immer genau. Damit wird es unmöglich die gesamten Daten "zusammenzupacken".

Oder hat jemand doch ein Stück Quelltext?

Beste Grüße
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
462 Beiträge
 
Delphi 2009 Professional
 
#5

AW: Socket C&S

  Alt 6. Feb 2018, 21:45
Irgendwie so (nicht getestet):
Delphi-Quellcode:
var
  buf: TBytes;
  len: Integer;
begin
  // bla bla
  len := Length(buf);
  SendBuf(len, 4);
  SendBuf(buf[0], Length(buf));
end;
Delphi-Quellcode:
var
  buf: TBytes;
  len: Integer;
begin
  Socket.ReceiveBuf(len, 4);
  SetLength(buf, len);
  Socket.ReceiveBuf(buf[0], len);
  // bla bla
end;
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.611 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#6

AW: Socket C&S

  Alt 6. Feb 2018, 21:47
ReceiveLength enthält die Größe der ankommenden Daten. Aber wie du schon korrekt erkannt hast, wird ein Send manchmal in mehrere Recv s aufgeteilt sozusagen. Die Summe aller ReceiveLength s entspricht dann der bei Send angegebenen Gesamtgröße.

Der Trick ist, dass du die Größe manuell einmal mitschickst, wie ich oben schon beschrieben habe.

Irgendwie so (nicht getestet)
Von der Idee her ja, allerdings müssen die Besonderheiten beachtet werden, die ich oben beschrieben habe. Also man benötigt auf jeden Fall eine Schleife, da auch mehrere Pakete "in einem Rutsch" ankommen können. Ich gucke gleich mal, ob ich noch einen alten Beispielcode finde.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.611 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#7

AW: Socket C&S

  Alt 6. Feb 2018, 23:00
Dieses Beispiel solltest du 1 zu 1 auf Sockets übertragen können:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    ...
  strict private
    FBuffer: TMemoryStream;
    FBufferLen: UInt32;

...

procedure TForm1.Recv(const Data: TBytes);
type
  PUInt32 = ^UInt32;
var
  N: UInt32;
  S: String;
begin
  // Erstmal alle Daten in den Buffer schreiben
  FBuffer.Write(Data, Length(Data));
  Inc(FBufferLen, Length(Data));

  // Pakete parsen
  while (FBufferLen >= SizeOf(N)) do
  begin
    N := PUInt32(FBuffer.Memory)^;
    if (FBufferLen < SizeOf(N) + N) then
    begin
      Break;
    end;
    // Mindestens ein Paket vollständig angekommen
    SetLength(S, N div SizeOf(Char));
    CopyMemory(@S[1], PByte(FBuffer.Memory) + SizeOf(N), N);
    ShowMessage(S);

    // Jetzt muss das bearbeitete Paket aus dem Buffer "entfernt" werden
    CopyMemory(FBuffer.Memory, PByte(FBuffer.Memory) + SizeOf(N) + N,
      FBufferLen - SizeOf(N) - N);
    Dec(FBufferLen, SizeOf(N) + N);
    FBuffer.Position := FBuffer.Position - SizeOf(N) - N;
  end;
end;
Hier noch zwei Testvektoren:
Delphi-Quellcode:
procedure TForm1.TestFragmented;
const
  S = 'Dieser String wird mehreren Paketen gesendet';
  X = 40;
var
  N: UInt32;
  D, F1, F2: TBytes;
begin
  N := Length(S) * SizeOf(Char);
  SetLength(D, SizeOf(N) + N);
  Move(N, D[0], SizeOf(N));
  Move(S[1], D[SizeOf(N)], N);
  SetLength(F1, X);
  Move(D[0], F1[0], X);
  SetLength(F2, Length(D) - X);
  Move(D[X], F2[0], Length(D) - X);
  // Einzelnes Paket wird fragmentiert empfangen
  Recv(F1);
  Recv(F2);
end;

procedure TForm1.TestMultiple;
const
  S1 = 'Dies ist String 1';
  S2 = 'Dies ist String 2';
var
  N1, N2: UInt32;
  D: TBytes;
begin
  N1 := Length(S1) * SizeOf(Char);
  N2 := Length(S2) * SizeOf(Char);
  SetLength(D, SizeOf(N1) + N1 + SizeOf(N2) + N2);
  Move(N1, D[0], SizeOf(N1));
  Move(S1[1], D[SizeOf(N1)], N1);
  Move(N2, D[SizeOf(N1) + N1], SizeOf(N2));
  Move(S2[1], D[SizeOf(N1) + N1 + SizeOf(N2)], N2);
  // Zwei Pakete werden als einzelnes Paket empfangen
  Recv(D);
end
Ich verwende hier absichtlich das extra Feld FBufferLen statt direkt FBuffer.Size , um frequente Speicher-Allocs zu vermeiden.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
tomkupitz

Registriert seit: 26. Jan 2011
146 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: Socket C&S

  Alt 7. Feb 2018, 10:55
Puffer zusammenpacken ist an sich kein Problem. Nur der Bezug zum Socket war mir wichtig.

Es sieht so aus, als wäre die max. Größe eines Blocks ein High(Word). Ich werde versuchen schon beim Versenden diese max. Blockgröße nicht zu überscheiten.
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
3.672 Beiträge
 
Delphi XE3 Ultimate
 
#9

AW: Socket C&S

  Alt 7. Feb 2018, 11:18
Vielleicht hilft Dir der Thread noch etwas weiter: http://www.delphipraxis.net/190482-s...ockettest.html
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.611 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#10

AW: Socket C&S

  Alt 7. Feb 2018, 14:04
Es sieht so aus, als wäre die max. Größe eines Blocks ein High(Word). Ich werde versuchen schon beim Versenden diese max. Blockgröße nicht zu überscheiten.
Versuch dein Glück, wenn du auf Redeemer und mich nicht hören willst, aber erwarte nicht, dass es zuverlässig funktioniert.

Die 65k bzw. mitlerweile meisten 256k, von denen man öfters mal liest, beziehen sich auf die Größe des internen Empfangs-Buffers unter Windows und nicht auf die MTU. Die EINZIGE zuverlässige Methode bei TCP ist eine eigene Pakettrennung. Denn selbst, wenn du es schaffen würdest dich immer korrekt an der MTU zu orientieren, dann schützt dich das weiterhin nicht davor, dass mehrere kleine Pakete zu einem großen Datenblock auf Empfängerseite zusammengefügt werden.

Mein Beispiel verwendet zwar keine Sockets, simuliert aber beide der primären Situationen, die beim Versand von Daten per TCP Socket auftreten und ist demnach absolut das, was du haben möchtest. Die Recv Methode kannst du praktisch 1 zu 1 übernehmen und mit den Daten des Sockets füllen und beim Send schickst du halt schnell einen UInt32 mit der Gesamtdatenmenge des Pakets vorweg. Ist kein großer Aufwand.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl ( 7. Feb 2018 um 14:06 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:17 Uhr.
Powered by vBulletin® Copyright ©2000 - 2019, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2019 by Daniel R. Wolf