![]() |
AW: Spielwiese - SocketTest
Liste der Anhänge anzeigen (Anzahl: 2)
Ok, hier mal das Projekt (XE3 und Exen) und ein neues Video:
![]() Das Video dauert 40 min. Es ist also sicher nur interessant für diejenigen, die an asynchroner Kommunikation direktes Interesse haben. (Dies ist übrigens mein 4. Aufnahmeversuch gewesen, da ich bei vorherigen Versuchen diverse Probleme und Abbrüche bis hin zu einem BlueScreen hatte. Also bitte seht mir nach, wenn es nicht so ganz strukturiert ist. Der Nerv-Faktor war schon etwas erhöht. :? Notfalls kann ich ja nochmal nachliefern.) Ich denke, der Ansatz könnte ganz tauglich sein. Aber sicher sind noch einige Bugs und Optimierungsmöglichkeiten vorhanden. Auch das Problem mit dem gelegentlichen Fehler beim Abmelden eines Clients konnte ich noch nicht vollständig lösen. Da ich das Konzept jetzt mal in einem anderen Projekt umsetzen will würde mich mal interessieren, was Ihr dazu meint und wer daran auch selbst Interesse hat. Insbesondere ist natürlich interessant, wenn Ihr hier Probleme erkennt bzw. Lösungen für diese habt. Natürlich ist das Projekt recht komplex und umfangreich, aber wenn wir eine stabile Version erreichen könnte das m.E. ein sehr nützliches Package für eine allgemeine und einfache asynchrone Kommunikation werden. Es wäre also nett, wenn Ihr mal Rückmeldungen bezüglich Interesse und Verbesserungen gebt. Gruß Stahli |
AW: Spielwiese - SocketTest
Ich nutze das Paket jetzt etwas erweitert in einem realen Programm. Das macht auf meinem Win10-Rechner und Win10-Laptop auch schon einen sehr guten Eindruck.
Auf meinem dienstlichen Rechner (Win7 Prof, 32bit) werden im Client aber nicht alle Daten dargestellt. Teilweise funktioniert es, aber nicht vollständig oder nur kurze Zeit. Eine TCP-Verbindung besteht zumindest anfangs mal. Welche einfachste Möglichkeit gibt es, den TCP-Traffic von außen zu loggen (ohne selbst etwas einzubauen)? Wenn ich sehen würde, ob überhaupt noch Nachrichten ausgetauscht werden, könnte ich das Problem vielleicht schon mal etwas eingrenzen. Ich habe hier keine Adminrechte und kann daher nichts installieren. Gibt es dennoch eine Möglichkeit, den Traffic etwas einzusehen? |
AW: Spielwiese - SocketTest
Zitat:
![]() EDIT: Zitat:
Aber vielleicht gibt es ja eine Version die als Portable genutzt werden kann. :| EDIT 2: Ja auf der DownloadSeite gibt es eine ![]() |
AW: Spielwiese - SocketTest
Vielen Dank.
Ich habe mir jetzt aber doch ein eigenes provisorisches Logging eingebaut (aus Zeitgründen noch nicht fertig). Ich kann schon mal sehen, dass beim Client nicht alles ankommt. Wird irgendwas beim Server klemmen. Mal schauen... |
AW: Spielwiese - SocketTest
Bei den non-blocking Sockets musst du beim Senden aufpassen:
Zitat:
Zitat:
![]() Was zusätzlich immer passieren kann (blocking und non-blocking), dass die Daten eines einzigen send()-Aufrufs in mehreren recv()-Aufrufen ankommen. Irgendeine Form von Pakettrennung muss man also zwingend selbst implementieren (Längenbasiert oder anhand von Trennzeichen). Aber das machst du soweit ich mich erinnere ja indirekt mit deinen String-Listen. |
AW: Spielwiese - SocketTest
Ich habe den Übeltäter. ;-)
Längere Texte werden ggf. bei der Übertragung gesplittet. Mein Handler hatte hier noch einen Bug und hat die unvollständigen Teile schon verarbeitet. Das Problem trat auf meinen 2 Rechnern nicht auf, aber bei allen anderen getesteten. Das lag wohl daran, wie die einzelnen Threads jeweils zeitlich zum arbeiten kommen. Also falls das jemand nutzen will dann hier ein Bugfix:
Delphi-Quellcode:
function TsoConnectionStringList.GetNextSL: TStringList;
var C: Integer; begin fCS.Enter; try if (fIndex < fItems.Count) then begin C := StrToInt(fItems[fIndex]); fItems[fIndex] := ''; Inc(fIndex); Result := TStringList.Create; while (C > 0) do begin Result.Add(fItems[fIndex]); fItems[fIndex] := ''; Inc(fIndex); Inc(fTransferCounter); Dec(C); end; if (fIndex >= fItems.Count) then begin fItems.Clear; fIndex := 0; end else begin if (fIndex > 1000) then begin while (fItems.Count > 0) and (fItems[0] = '') do begin fItems.Delete(0); Dec(fIndex); end; end; end; end else Result := nil; finally fCS.Leave; end; end; |
AW: Spielwiese - SocketTest
Die letzte Änderung reicht doch nicht aus.
Also mein Konzept ist gut einsetzbar für kurze Stringlisten-Messages. Wem das ausreicht, der kann das gut einsetzen. Längere Stringlisten werden aber von den Sockets in 2 oder mehr Teilen übertragen und auf Grund der Zeilenumbrüche nicht immer korrekt zusammengesetzt. Wer also auch längere Stringlisten übertragen will braucht eine alternative Lösung. Ich bin daher dabei, die Stringlisten in Streams zu speichern und die Streams zu übertragen. Das hat auch den Vorteil, dass man die Streams bei Bedarf leichter komprimieren bzw. verschlüsseln kann. Orientiert habe ich mich an folgendem Beitrag: ![]() Jetzt habe ich das Problem, dass Read(...) manchmal feuert, Socket.ReceiveLength aber 0 ist und entsprechend keine Daten geladen werden können. Read(...) feuert aber später nicht noch einmal, so dass Daten verloren gehen. Wenn ein Stream vollständig angekommen ist wird er wieder in eine StringList geschrieben und in eine Queue gehängt zur weiteren Verarbeitung durch Threads. Kann sein, dass ich hier etwas verbockt habe, aber in der Nacht konnte ich da nichts mehr finden. Eigentlich sollten die Verarbeitungsthreads ja die Eriegnisbehandlung im Mainthread nicht stören. Solange ich Strings übertragen hatte war das auch nicht der Fall. (Blöderweise spinnt mein USB-Stick schon wieder, so dass ich hier gerade keinen Code dabei habe und ihn gerade nicht posten kann.) Hat jemand so pauschal eine Idee, wie das Problem Socket.ReceiveLength=0 zu lösen ist? |
AW: Spielwiese - SocketTest
Zitat:
Delphi-Quellcode:
Operationen des Buffers zu minimieren. Beispielsweise könntest du noch ein zustäzliches Feld
Realloc
Delphi-Quellcode:
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
BufferPos
Delphi-Quellcode:
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
@Buffer[BufferPos]
Delphi-Quellcode:
verzichten kannst.
Realloc
Edit: Achso und wie sieht deine Sende-Routine aus? Bei non-blocking Sockets kann ![]() ![]() |
AW: Spielwiese - SocketTest
Sind es blocking oder non-blocking Sockets?
Zitat:
Blockierender Ansatz wäre eigentlich so: Server (wie im Original):
Delphi-Quellcode:
Client:
var
lLen: Integer; lStream: TStream; begin lStream := TFileStream.Create('c:\testbild.bmp', fmOpenRead); lLen := lStream.Size; // grösse Stream ermitteln Socket.SendBuf(lLen, SizeOf(lLen)); // Grösse senden Socket.SendStream(lStream); // dann das Bild hinten dran... end;
Delphi-Quellcode:
Der nicht-blockierende Ansatz wäre so wie Zacherl beschrieben hat.
var
lLen: Integer; lStream: TStream; Buffer: Pointer; begin Socket.RecvBuf(lLen, SizeOf(lLen)); lStream := TFileStream.Create('c:\testbild.bmp', fmOpenWrite); // Im einfachsten Fall. Besser wäre es natürlich, einen Buffer fester Größe // zu erzeugen und mit einer Schleife zu arbeiten, damit der RAM nicht gesprengt wird. GetMem(Buffer, lLen); Socket.ReceiveBuf(Buffer^, lLen); lStream.Write(Buffer^, lLen); FreeMem(Buffer); lStream.free; end; Wieso genau der Fehler bei dir kommt, weiß ich nicht, aber ich hatte ja schon mal geschrieben, dass blockierend und eventgetrieben sich nicht gut verträgt. |
AW: Spielwiese - SocketTest
Liste der Anhänge anzeigen (Anzahl: 1)
Meine Anwendung ist nicht blockierend.
Ich habe gestern erst mal meinen bisherigen Ansatz in einer repeat-Schleife gepackt und den Ablauf etwas geloggt. Im Eingang in die Methode hat ReceiveLength z.B. 8 ausgegeben. Drei Zeilen weiter dann ggf. 100. Also verändert sich der Wert auch schon mal dynamisch. Until habe ich dann bei "ReceiveLength = 0" veranlasst. Im Ergebnis holt sich die Behandlung zunächst einen Integerwert für die Streamgröße sobald 4 Bytes verfügbar sind und den Stream selbst sobald dieser komplett verfügbar ist. So sollte das m.E. ja eigentlich funktionieren - hat es auch. Aber sobald ich die Logs raus genommen habe lief es wieder nicht mehr. Da muss wohl irgendwo anders noch ein (Thread-)Problem sein. In der Nacht um 3 habe ich dann erst mal aufgegeben. :-/ Hier mal der Quelltext (mit dem Logging), der funktionierte. PS: Ich schaue mir auch Zacherls Hinweis nochmal an, aber ich dachte, meine aktuelle Lösung würde quasi das Gleiche machen...
Delphi-Quellcode:
...Send
MS := TMemoryStream.Create; lSL.SaveToStream(MS); MS.Seek(0, soBeginning); MSSize := MS.Size; fServerSocket.Socket.Connections[I].SendBuf(MSSize, SizeOf(MSSize)); if fServerSocket.Socket.Connections[I].SendStream(MS) then LogSL('==>', '', lSL) else LogSL('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==>', '', lSL); //============================================== ...Read var iLen: Integer; Bfr: Pointer; SL: TStringList; lP: Int64; rl: Integer; iL: Integer; begin if fff then Codesite.Send('ffffffffffffffffffffffffffff'); fff := True; repeat rl := Socket.ReceiveLength; Codesite.Send('Read: ' + IntToStr(rl)); Codesite.Send('a: ' + IntToStr(Socket.ReceiveLength)); if not Assigned(fMS) then begin Codesite.Send('not Assigned(fMS)'); if Socket.ReceiveLength >= SizeOf(fMSSize) then begin Codesite.Send('Socket.ReceiveLength >= SizeOf(fMSSize)'); iL := Socket.ReceiveBuf(fMSSize, SizeOf(fMSSize)); Codesite.Send('reading=' + IntToStr(iL)); fMS := TMemoryStream.Create; end else Codesite.Send('NOT Socket.ReceiveLength >= SizeOf(fMSSize)'); end else Codesite.Send('NOT not Assigned(fMS)'); Codesite.Send('b: ' + IntToStr(Socket.ReceiveLength)); if Assigned(fMS) then begin Codesite.Send('Assigned(fMS)'); iLen := Socket.ReceiveLength; Codesite.Send('*** ' + IntToStr(iLen) + '/' + IntToStr(fMSSize)); iLen := Min(fMSSize, iLen); GetMem(Bfr, iLen); try iL := Socket.ReceiveBuf(Bfr^, iLen); Codesite.Send('reading=' + IntToStr(iL)); Dec(fMSSize, fMS.Write(Bfr^, iLen)); if Socket.ReceiveLength > 0 then begin Codesite.Send('!!!REST'); end; // lP := fMS.Position; // fMS.Position := 0; // SL := TStringList.Create; // SL.LoadFromStream(fMS); // SL.Insert(0, IntToStr(SL.Count)); // LogSL('<--', '', SL); // FreeAndNil(SL); // fMS.Position := lP; finally FreeMem(Bfr); end; Codesite.Send('c: ' + IntToStr(Socket.ReceiveLength)); if fMSSize = 0 then begin Codesite.Send('fMSSize = 0'); fMS.Position := 0; SL := TStringList.Create; SL.LoadFromStream(fMS); SL.Insert(0, IntToStr(SL.Count)); FreeAndNil(fMS); fMessageHandlerServer.RegisterInSL(SL, Socket); FreeAndNil(SL); end else Codesite.Send('NOT fMSSize = 0'); end else Codesite.Send('NOT Assigned(fMS)'); Codesite.Send('----: ' + IntToStr(Socket.ReceiveLength)); until (Socket.ReceiveLength = 0); Codesite.Send('----------------------: ' + IntToStr(Socket.ReceiveLength)); fff := false; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:58 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz