| Autor |
Beitrag |
oern
      
Beiträge: 142
Linux, Win XP
D7
|
Verfasst: Mo 03.07.06 13:07
Ich habe das UDPSockUtil bisher verwendet um records zu versenden.
Aufgrund von diesen Beitrag und das der record zu groß ist möchte ich nicht mehr. Ich möchte nun die Daten Binär über tragen, da mir diese methode als am schnellsten erscheint.
z.Z gehe ich denn umweg über einen stream ich packe zu erste einen Command Integer in den stream und dann alles was für das command gebraucht(single werte etc.). Das wird dann alles in einen array of byte gepacket und mit SendBuf geschickt (so soll es zumindest werden)
Leider kommt da nichts vernüftiges an
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
| procedure TGLSN_Engine.UDPBroadcastStream(S: TMemoryStream); var b: array of byte; begin setlength(b, s.Size); s.Read(b, s.Size); UdpSockUtil.SendBuf(b, sizeof(b)); end;
procedure TGLSN_Engine.UdpSockUtilReceive(Sender: TObject); var Len: Integer; vonIP: in_addr; b: array of byte; s: TMemoryStream; C: Integer; begin Len := UdpSockUtil.ReceiveLength; if (Len >= 4) then begin begin setlength(b, len); UdpSockUtil.ReceiveBuf(b, sizeof(b), vonIP); try s:= TMemoryStream.Create; s.Write(b, sizeof(b)); s.Read(c, sizeof(c)); finally s.Destroy; end; end; end; end;
procedure TGLSN_Engine.StartServer; var s: TMemoryStream; i: integer; begin Server.Open; try s:= TMemoryStream.Create; i:= 1; s.Write(i, SizeOf(Integer) ); UDPBroadcastStream(s); finally s.Destroy; end; end; |
Was mache ich da nur falsch ?
mfg, Björn
_________________ Ich hab eine Signatur
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 03.07.06 14:33
Moin!
Sorry, bitte nicht persönlich nehmen, aber du wagst dich da mit deinem Wissensstand an ein Problem heran, das dir (z.Zt. wohl noch) ein bis zwei Nummern zu gross ist...
Ich will dir zunächst mal nur den Fehler zeigen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TGLSN_Engine.UDPBroadcastStream(S: TMemoryStream); var b: array of byte; BytesSent: Integer; begin setlength(b, s.Size); s.Read(b, s.Size); BytesSent := UdpSockUtil.SendBuf(b, sizeof(b)); ShowMessage(IntToStr(BytesSent)); end; |
Wenn du das ausführst, wirst du vermutlich eine "0" angezeigt bekommen, was bedeuten soll, dass keine Bytes übertragen wurden - zumindest aber wird dir dieser Code zeigen, dass du nicht die Menge Bytes gesendet hast, die du senden wolltest. Das könnte - wie du schon gesagt hast - daran liegen, dass du mehr als 512 Bytes (bzw. besser die Konstante USU_MAX_DGRM_SIZE nehmen) senden willst, was UDP nicht kann. Du mußt also in diesem Fall selbst für die Segmentierung sorgen. Vor allem aber mußt du auch schauen, ob du alles was du senden wolltest, auch gesendet hast (den Rückgabewert von SendBuf auswerten).
Nächstes Problem (in folgedesssen): Wenn du mit UDP-Paketen arbeitest, dann muss dir klar sein, dass die Sendereihenfolge nicht zwingend die Empfangsreihenfolge abbildet - es könnten sogar schlimmstenfalls Pakete fehlen!  Du mußt also eine eigene Sicherungsschicht implementieren (dein Stream muss ja konsistent bleiben, sonst ist er wertlos), und das wird nicht ganz einfach sein.
Deshalb mein Tipp für dich: Wickle nur die Signalisierung über UDP-Broadcasts ab und mach den Datentransfer mit TCP-Verbindungen direkt an die entsprechenden IPs, sonst kommst du in Teufelsküche!
Der Ansatz mit dem Stream als record-Ersatz ist ja schon ganz nett, aber wesentlich einfacher wäre ein Protokoll, das ich dir hiermit nochmal ans Herz legen möchte.  Das ganze gibt´s übrigens auch in der UDP-Variante.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
oern 
      
Beiträge: 142
Linux, Win XP
D7
|
Verfasst: Mo 03.07.06 15:06
| Zitat: | Sorry, bitte nicht persönlich nehmen, aber du wagst dich da mit deinem Wissensstand an ein Problem heran, das dir (z.Zt. wohl noch) ein bis zwei Nummern zu gross ist... |
Das kann sein bzw. ist bestimmt so. Aber ich habe mich auch durch die 3D darstellung gekämpft.
| Zitat: | | Wenn du das ausführst, wirst du vermutlich eine "0" angezeigt bekommen, was bedeuten soll, dass keine Bytes übertragen wurden - zumindest aber wird dir dieser Code zeigen, dass du nicht die Menge Bytes gesendet hast, die du senden wolltest. Das könnte - wie du schon gesagt hast - daran liegen, dass du mehr als 512 Bytes (bzw. besser die Konstante USU_MAX_DGRM_SIZE nehmen) senden willst, was UDP nicht kann. Du mußt also in diesem Fall selbst für die Segmentierung sorgen. Vor allem aber mußt du auch schauen, ob du alles was du senden wolltest, auch gesendet hast (den Rückgabewert von SendBuf auswerten). |
Nach BytesSent werden 4 byte gesendet also die größe eines integers.
| Zitat: | Nächstes Problem (in folgedesssen): Wenn du mit UDP-Paketen arbeitest, dann muss dir klar sein, dass die Sendereihenfolge nicht zwingend die Empfangsreihenfolge abbildet - es könnten sogar schlimmstenfalls Pakete fehlen! Du mußt also eine eigene Sicherungsschicht implementieren (dein Stream muss ja konsistent bleiben, sonst ist er wertlos), und das wird nicht ganz einfach sein. |
Wenn ich pro Sekunde 30 Pakete sende dann können da ruhig 1 oder 2 wegkommen müssen halt nur so 24 ankommen damit alles flüssig läuft.
| Zitat: | Der Ansatz mit dem Stream als record-Ersatz ist ja schon ganz nett, aber wesentlich einfacher wäre ein Protokoll, das ich dir hiermit nochmal ans Herz legen möchte. Das ganze gibt´s übrigens auch in der UDP-Variante. |
Ich arbeiten an eine shooter da müssen viele daten über das netzwerk gesendet werden und die CPU wird immer sehr stark belastet (immer 100%), ich denke dann strings parsen wäre zu viel rechen aufwand. Dann wär noch der Traffic durch das Protokoll höher als durch binäre daten da vieles im klartext übertragen wird oder liege ich da falsch ?
mfg, Björn
_________________ Ich hab eine Signatur
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 03.07.06 15:36
Moin!
oern hat folgendes geschrieben: | | Wenn ich pro Sekunde 30 Pakete sende dann können da ruhig 1 oder 2 wegkommen müssen halt nur so 24 ankommen damit alles flüssig läuft. |
Ja, das ist korrekt gedacht; allerdigs: du willst einen Stream übertragen, der größer als die maximale UDP-Paketgröße ist -> mehrere Pakete -> davon darf dann aber keins fehlen, sonst ist der Stream ja nicht vollständig -> Sicherungsschicht!
Alternative: nie mehr als max. Paketgröße auf einmal (zusammenhängend) senden.
oern hat folgendes geschrieben: | | Ich arbeiten an eine shooter da müssen viele daten über das netzwerk gesendet werden und die CPU wird immer sehr stark belastet (immer 100%), ich denke dann strings parsen wäre zu viel rechen aufwand. Dann wär noch der Traffic durch das Protokoll höher als durch binäre daten da vieles im klartext übertragen wird oder liege ich da falsch? |
Naja, vom Grundsatz her hast du schon recht, allerdings kommt es immernoch darauf an, wie "komplex" der Parser denn gestrickt ist, und ob das Strings sein müssen, es lassen sich ja auch Binärdaten transportieren. Aber ganz allgemein: ich glaube nicht, dass der Protokollparser den Kohl fett macht, bei einer solchen Grafikanwendung, da sind andere Dinge, die die Last erzeugen.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
oern 
      
Beiträge: 142
Linux, Win XP
D7
|
Verfasst: Mo 03.07.06 18:40
Ich hab alle Fehler gefunden und es funktioniert
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53:
| procedure TGLSN_Engine.UDPBroadcastStream(S: TMemoryStream); var b: array of byte; BytesSent: Integer; begin setlength(b, s.Size); s.Position:=0; s.Read(b[0], s.Size); BytesSent:=UdpSockUtil.SendBuf(b[0], sizeof(b)); if Loging then begin if BytesSent=0 then begin LogMsg('UDP Error: 0 Byte gesendet.'); end; if BytesSent>512 then begin LogMsg('UDP Warnung: Paketgröße von 512 Bytes überschriten.'); end; end; end;
procedure TGLSN_Engine.UdpSockUtilReceive(Sender: TObject); var Len: Integer; vonIP: in_addr; b: array of byte; s: TMemoryStream; C: Integer; begin Len := UdpSockUtil.ReceiveLength; if (Len >= 4) then begin begin setlength(b, len); UdpSockUtil.ReceiveBuf(b[0], sizeof(b), vonIP); try s:= TMemoryStream.Create; s.Write(b[0], sizeof(b)); s.Position:=0; s.Read(c, sizeof(c)); case C of GLSN_StartServer:begin IPList.addip(inet_ntoa(vonIP)); end; else end; finally s.Destroy; end; end; end; end; |
| Zitat: | | Ja, das ist korrekt gedacht; allerdigs: du willst einen Stream übertragen, der größer als die maximale UDP-Paketgröße ist -> mehrere Pakete -> davon darf dann aber keins fehlen, sonst ist der Stream ja nicht vollständig -> Sicherungsschicht! |
Solange ich über die UDP Verbindung nur Pakete kleiner 512 Byte sende hab ich damit keine problem, und die positionen belegen nur so um die 20 Byte.
| Zitat: |
Naja, vom Grundsatz her hast du schon recht, allerdings kommt es immernoch darauf an, wie "komplex" der Parser denn gestrickt ist, und ob das Strings sein müssen, es lassen sich ja auch Binärdaten transportieren. Aber ganz allgemein: ich glaube nicht, dass der Protokollparser den Kohl fett macht, bei einer solchen Grafikanwendung, da sind andere Dinge, die die Last erzeugen. |
Aber dennnoch schlägt ein protokol mit ein paar byte zu buche, die man vermeiden kann.
mfg, Björn
_________________ Ich hab eine Signatur
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 03.07.06 22:55
Moin!
oern hat folgendes geschrieben: | Ich hab alle Fehler gefunden und es funktioniert  |
Schön; ich habe ja auch nicht behauptet, dass es nicht geht.
oern hat folgendes geschrieben: | | Solange ich über die UDP Verbindung nur Pakete kleiner 512 Byte sende hab ich damit keine problem, und die positionen belegen nur so um die 20 Byte. |
Genau das habe ich geschrieben...
oern hat folgendes geschrieben: | | Aber dennnoch schlägt ein protokol mit ein paar byte zu buche, die man vermeiden kann. |
Sorry, aber IMHO sind weder die paar Bytes Protokolloverhead noch die paar Nanosekunden das, was dir die "Zeit klaut". Da halte ich schon eher die Windows-Nachrichtenverarbeitung, die du implizit über meine Komponente verwendest, für einen Performance-Fresser. Wenn du wirklich auf dieser Ebene optimieren willst, dann mußt du blocking-socket-calls machen und mit Threads arbeiten. Mit den WSA-Messages vergräbst du SEHR VIEL mehr Zeit, als dich jeder Protokoll-Parser jemals kosten könnte.
cu
Narses
PS: Wenn dein Problem gelöst ist, markierst du den Thread dann noch entsprechend? Danke. 
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 04.07.06 11:25
Moin!
Was mir noch (später) aufgefallen ist: du kannst das Versenden vermutlich leichter mit einem TStringStream abwickeln, so z.B.:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TForm1.Button1Click(Sender: TObject); var StrStream: TStringStream; IntVar: Integer; DoubleVar: Double; begin StrStream := TStringStream.Create(''); IntVar := $4711; StrStream.Write(IntVar,SizeOf(IntVar)); DoubleVar := 1.41421; StrStream.Write(DoubleVar,SizeOf(DoubleVar)); StrStream.WriteString('Test'); if (UdpSockUtil1.SendText(StrStream.DataString) <> StrStream.Size) then ShowMessage('Fehler beim Senden!'); StrStream.Free; end; |
Damit sparst du dir den zusätzlichen Speicher und das Kopieren (du bist doch so ein Optimierungsfuchs...  ).
Beim Empfangen solltest du auch dann Lesen, wenn weniger als 4 Bytes eintreffen. Ist dann halt eine Fehlersituation, aber irgendwohin sollten die Daten schon "verschwinden":
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TForm1.UdpSockUtil1Receive(Sender: TObject); var StrStream: TStringStream; vonIP: in_addr; IntVar: Integer; begin StrStream := TStringStream.Create(UdpSockUtil1.ReceiveText(vonIP)); StrStream.Position := 0; if (StrStream.Size >= 4) then begin StrStream.Write(IntVar,SizeOf(IntVar)); case IntVar of $4711: ShowMessage('Echt komisches Wasser!'); else ShowMessage('Keine Ahnung!?'); end; end else ShowMessage('Zu wenig Daten gelesen!'); StrStream.Free; end; |
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
oern 
      
Beiträge: 142
Linux, Win XP
D7
|
Verfasst: Di 04.07.06 11:33
Danke den Type kannt ich gar nicht 
_________________ Ich hab eine Signatur
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 04.07.06 12:06
Moin!
Wenn dein Problem gelöst ist, markierst du den Thread dann noch entsprechend? Danke.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
|