![]() |
Sehr langen String mit Clientsocket an Serversocket senden..
Ich möchte gern den Inhalt einer Listbox über die Clientsocket Kombo an eine Serversocket Kombo schicken und dann wieder in einer anderen Listbox Speichern. Dazu versende ich einfach den CommaText und das ist soweit auch gar kein Problem. Wenn der Comatext der ersten Listbox jedoch eine bestimmte Zeichenanzahl übersteigt, wird der der Sendestring nicht mehr als ein Packet abgeschickt, sonder in mehrere Teiler zersplittet. Nun wird es recht schwer den Comatext einfach im ServerSocket1ClientRead zu speichern, da
Code:
bewirken würde, dass nur das letzte Teilpacket in der Serverlistbox gespeichert wird.
Serverlistbox.items.comatext := socket.ReceiveText
Naja ich habe das jetzt so gemacht, dass ich bevor ich den String verschicke, vorhänge wie viele Zeichen der String hat und dann später vergleiche: Hat der empfangene Comatext die Zeichenanzahl des versendeten Comatexts, dann ist alles Prima, ansonsten soll immer wenn ein neues Stringpacket empfangen wird dieses an den Comatext rangehängt werden ... halt eben so lange bis Server Comatext gleich Client Comatext ist. Mh.. ich schätze jetzt peilt keiner, gar nichts mehr... also zeig ich mal meinen Code;
Code:
// Zum Versenden procedure Clientform.Button1Click(Sender: TObject); VAR send : STRING; BEGIN send := '±±±'+ inttostr(length(Clientlistbox.Items.CommaText)) + '±±±' + Clientlistbox.Items.CommaText; socket.SendText(send); END; // Emphangen procedure Serverform.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); VAR s, sh : STRING; i : INTEGER; begin s := socket.ReceiveText;; FOR i := 1 TO 3 DO sh := sh + s[i]; IF sh = '±±±' THEN BEGIN all := FALSE; // Global delete(s,1,3); laenge := strtoint(copy(s, 1,pos('±±±',s)-1)); delete(s,1,pos('±±±' ,s) + 2); coma := coma + s; // Global s := ''; if length(coma) = laenge THEN BEGIN all := TRUE; // Global Serverlistbox.Items.CommaText := coma; socket.Close; END; END; IF all <> TRUE THEN BEGIN coma := coma + s; if length(coma) = laenge THEN BEGIN all := TRUE; // Global Serverlistbox.CommaText := coma; socket.Close; END; END; END; Also das funktioniert soweit auch alles Prima. Nur kommt mir das ein wenig zu kompliziert vor, es muss doch auch einen einfacheren Weg geben um lange Strings übers Netz zu versenden, oder?! Hat Jemand eine Idee?! |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo,
der Ausweg ist TWinSocketstream. Dafür musst Du eine blockierende Verbindung verwenden. ISt sowieso besser. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Öhm hast Du dafür ein Beispiel oder so?! Kann mir darunter nichts
Richtiges vorstellen. Mit Strams hab ich noch nicht wirklich gearbeitet.. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo,
ein Beispiel habe ich z.Z. nicht. Diese Beispiele erstecken sich immer über endlos viele Codezeilen. Dadurch sind sie immer ziemlich unverständlich. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Naja bei Google gibt es zum Thema "TWinSocketstream" nicht wirklich was, dass den umgang damitt vertändlich erklärt. Und die Delphi Hilfe beschreibt auch nur Allgemeinen Müll dazu :(
|
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
|
Re: Sehr langen String mit Clientsocket an Serversocket send
Und wie soll ich dann damitt arbeiten, wenn ich keine Ahnung habe wie´s funktioniert?! *g*
|
Re: Sehr langen String mit Clientsocket an Serversocket send
Ich habe sowas schon mal gemacht.
Dafür habe ich TClient- und TServerSocket verwendet. Ich viele kleine Testprogramme geschrieben, bis ich kapiert habe wie es geht. Das ist aber schon solange her, dass ich mich in das Thema wieder einarbeiten muss um ein Beispiel zu produzieren. Ich dachte ich mach das mal schnell. Jetzt kann ich aber TClientSocket und TServersocket in der D7 Pro Komponentenpalette nicht finden. Ich habe D7 erst seit 5 Wochen. Wo sind die Komponenten geblieben ? |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
![]() MfG Christian |
Re: Sehr langen String mit Clientsocket an Serversocket send
Komponente -> Packages installieren -> Hinzufügen
und dann die dclsockets70.bpl aus dem Delphi-bin Verzeichnis laden ... und schwups sind die Sockets unter INTERNET wieder da. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo,
ich hatte kein Lust lange rum zu suchen. Deshalb habe mir eine kleine unit geschrieben und in ein Package gepackt. Diese Package habe ich installiert. Jetzt sind die Komponenten da.
Delphi-Quellcode:
unit MySocktes;
interface uses classes, ScktComp; procedure Register; implementation procedure Register; begin RegisterComponents('Sockets',[TClientSocket,TServerSocket]); end; end. |
Re: Sehr langen String mit Clientsocket an Serversocket send
*grins* Warum´s einfach machen, wenn´s auch kompliziert geht?! *g*
|
Re: Sehr langen String mit Clientsocket an Serversocket send
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe ich meinen Sourcen und meiner Erinnerung gekramt und ein Quick&Dirty Beispiel zusammengestellt. clSendTStrings.exe (Client) sendet über eine blockierende Verbindung und TWinSocketStream den Inhalt einer TListBox an svSendTStrings.exe (Server). Der Server lädt damit seine TLisbox. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Also wenn man große String-Daten verschickt und ganz ganau wissen will
wann und ob die komplett angekommen sind, sollte man am besten eine Anfang- und End- Signaturen verwenden. Irgendein Zeichen, das nicht in den vorkommen kann (z.B. HEX 13 und HEX 14 oder so). Dann speichert man jeden angekommenen Frame in ein Buffer und überprüft, ob Anfang und Ende im Buffer vorkommen, wenn das der Fall ist - Daten sind da, wenn nicht auf weitere Pakete warten. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Delphi-Quellcode:
habs net getestet müsste aber so gehen.
//Client
procedure TForm1.senden; var TextStream : TStringStream; begin textstream:=TStringStream.Create(ListBox1.CommaText); textstream.Position:=0; ClientSocket1.Socket.SendStream(textstream); end; //Server procedure TForm1.ServerSocket1ClientRead(Sender: TObject; Socket: TCustomWinSocket); var iLen: Integer; Bfr: Pointer; text: TStringStream; begin iLen := Socket.ReceiveLength; GetMem(Bfr, iLen); Socket.ReceiveBuf(Bfr^, iLen); text:=TStringStream.Create(''); text.Write(Bfr^, iLen); text.Position:=0; ListBox1.Lines.Add(text.DataString); end; |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Wenn die vom Client gesendete Datenmenge nicht in ein Paket passt, wird die Datenmenge aufgeteilt und mit mehreren Pakten versandt. Das führt dazu, dass das ClientRead Event mehr als einmal feuert. Was dann in der Listbox steht kann sich ja dann denken. Jetzt sage ich es zum letzen Mal: Blockierende Verbindungen und TWinsocketStream |
Re: Sehr langen String mit Clientsocket an Serversocket send
bei blocked sockets kann es aber genauso zu Fragmentierung kommen,
wenn die Daten groß sind, dann werden die je von TCP-Stack gesplittet, Netz dazwischen spielt auch ne Rolle. man muss auf jeden Fall selbst eigene Frames "verpacken", wie ich bereits oben geschrieben hab, mit Start- und End-Signaturen . |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Wenn der Client connected (Dann sendet der Client auch sofort) wird im OnGetThread von TServerSocket ein neuer TServerClientThread erzeugt. Dadurch wird dann im neuen TServerClientThread (oder aus dem Threadpool) die Methode ClientExecute aufgerufen. Das folgende Beispiel basiert übrigends auf dem Beispiel aus der OH.
Delphi-Quellcode:
procedure TClientThread.ClientExecute;
var szBuffer : array[0..1024] of Char; aWSStream : TWinSocketStream; iBytes : Integer; aMStream : TMemoryStream; DataPosition : Integer; begin FillChar(szBuffer, SizeOf(szBuffer), #0); while not Terminated and ClientSocket.Connected do begin try // Blockierende Sockets mit 60 Sekunden Timeout aWSStream := TWinSocketStream.Create(ClientSocket, 60000); aMStream := TMemoryStream.Create; try // Client muss innerhalb von 5 Sekunden mit der Übertragung beginnen if aWSStream.WaitForData(5000) then repeat iBytes := aWSStream.Read(szBuffer, SizeOf(szBuffer)); if iBytes = 0 then // Wenn keine Daten mehr aus der Verbindung gelesen werden können, // kappe die Verbindung zum Cient. Dadurch liefert auch WaitForData // False und die Repeat-Schleife wird verlassen. ClientSocket.Close else aMStream.WriteBuffer(szBuffer, iBytes); until not aWSStream.WaitForData(2000); // Solange aus Verbindung lesen, wie // wie Verbindung bereit ist. // Ab hier sind alle Daten, die gesendet wurden in aMStream !!!!! FStream.Clear; aMStream.Seek(0,soFromBeginning); // Der Client hat vor den eigentlichen Nutzdaten einen einen Record in den TWinSocketStream // geschrieben. Dieser Record enthält eine sog. CommandID. Dieser Record muss jetzt erstmal // aus aMStream gelesen werden. DataPosition:=aMStream.Read(FCommand,SizeOf(TClSvCommand)); // Kopiere jetzt ab Dataposition die Nutzdaten nach FStream FStream.CopyFrom(aMStream,aMstream.Size-DataPosition); // Entscheide über die CommandID was zu tun ist. Case FCommand.CommandID of iCommandLoadMemo : Synchronize(UpdateMemo); iCommandCLearMemo : Synchronize(ClearMemo); end; finally aWSStream.Free; ClientSocket.Close; aMStream.Free; end; except HandleException; end; end; end; |
Re: Sehr langen String mit Clientsocket an Serversocket send
das alles heißt ja nicht, dass die Daten nicht fragmentiert werden,
im Beispiel wird das nur dadurch gelöst, dass Du immer die Daten liest, solange es geht. Das geht auch, im Thread, und nur wenn du ein Frame in einer Stunde abschickst. Start und End-Signaturen sind immer wichtig, stell dir vor, Du willst zwei Memo-Felder oder was auch immer füllen, schickt Deine 2 Frames innerhalb 1 Sekunde ab und es kommen 3 Datenpackete (weil die unterwegs defragmentiert wurden), wie willst Du die bearbeiten, wenn Du nicht weiß wo der Anfang und das Ende sind? |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
|
Re: Sehr langen String mit Clientsocket an Serversocket send
Ich hab auch kein Wort über Reihenfolge geschrieben.
Es kann nur passieren, dass zwei abgeschickte Frames als drei Frames ankommen. Und daher muss man wissen, wo ein Frame (jetzt eigener Frame, Packet, und nicht TCP) anfängt und endet. Oder? |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Das ist völlig egal. Weil anschließend alles korrekt über TWinSocketStream eingelesen wurde. Das ist auch der Grund weshalb ich hier immer und immer wieder auf TWinSocketStream und blockierende Verbindungen hinweise. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Aus dem ganzen sieht man, dass Du noch nie richtig mit Sockets
gearbeitet hast, daher fehlt Dir auch das Verständis für solche Sachen. Ich schreibe seit Jahren Applikationen, die mehrere Tausenden von Datenframes innerhalb weniger Sekunden verschicken und weiß wovon ich rede. Mit der Zeit wirst Du das schon verstehen. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Beispiel
--------- Man verschickt zwei Kontakte über TCP/IP: Max,Muster,Neuer Weg 12 und Eva,Braun,Sternstrasse 14 beide Kontakte müssen z.B. in eine Datenbank abgespeichert werden. Daten, die ankommen sehe wie folgt aus: Max,Muster,Neuer Weg 12Eva,Braun,Sternstrasse 14 Wie machst Du das, wenn Du nicht weiß, wo ein Kontakt anfängt und wo der endet? Wenn Du aber: <start>Max,Muster,Neuer Weg 12<end> <start>Eva,Braun,Sternstrasse 14<end> verschickst. kannst Du nach <start> und <end> parsen. Nicht wahr? |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Ich hätte da für foldgenden Record in einer unit, die Client und Server verwenden:
Delphi-Quellcode:
Diesen Record würde ich auf der Clientseite entsprechend füllen.
TKontakt = Record
Vorname : String[20]; Nachname : String[25]; Strasse : String[40]; end; Wenn ich z.B. 5 Kontakte versenden möchte, würde ich die Kontakte in einem TMemoryStream sammeln. Die Kontakte werden dann über TWinSocketStream.CopyFrom(MemoryStream,0) zum Server befördert. Auf der Serverseite wird innerhalb die Repeat-Schleife der Inhalt der Verbindung über TWinsocketStream eingelesen (Siehe oben). Ob Du es glaubst oder nicht. Die einzelnen Kontakte stehen dann alle korrekt in FStream (siehe oben). Jetzt kann ich mit FStream.Read(aKontakt,SizeOf(TKontakt)) die einzelnen Kontake aus dem Stream lesen und in die Datenbank schieben. Evt. reden wir ja von unterschiedlichen Dingen :gruebel: |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo AnTiPrimaTe,
ich habe gerade etwas ausprobiert. Meine Testanwendung sendet zweimal unmittelbar hintereinander (ohne Sleep oder sowas) 100 Kb über TWinSocketStream an den Server. Die erste Sendung wird in Memo1 und die zweite Sendung in Memo2 angezeigt. Das erreiche ich dadurch, dass ich einen CommandRecord vor die Nutzdaten in den Stream schreibe (siehe oben). Kein Problem - klappt prima - P.S. Jetzt muss ich erstmal ne Runde Mountain-Bike fahren. Ich finde die Diskussion hoch interessant. Sollten wir fortführen. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Kontakte übertragen werden. Angenommen die Kontakte kommen in zufälligen Intervallen und zufälligen Mengen an. Sobald ein Kontakt ankommt, muss der in die DB. Wenn die Daten ungünstig fragmentiert werden, kann es passieren, dass nur die hälfte vom Record da ist (die andere kommt mit einer Verzögerung an). Wenn man in so einem Moment FStream.Read(aKontakt,SizeOf(TKontakt)) macht, fällt der Client auf die Schnauze ... also muss man warten, bis ein Record komplett da ist. Wie willst Du das feststellen ohne Signaturen? try ... except? Server und Client müssen ja gleichzeitig laufen und asynchron, das ist das Problem. Der Server schickt seine Sachen ab und der Client weiß nicht was auf den zukommt, das muss der selbst rausfinden, ob ein Kontakt da ist oder zwei und ob die komplett angekommen sind. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich glaube Du überliest geflissendlich das ich von blockierenden Verbindungen schreibe. Genau Dein Problem lässt damit bestens lösen. Wenn der Client nicht weiß wieviel Kontakte kommen schickt er eben jeden Kontakt einzeln ab. Ich habe es mit meinem Testprogramm gestestet was passiert wenn der Client ständig und unmittelbar hintereinander 100 kB Text an den Server sendet. Ich glaube das entspricht ungefähr Deiner Anforderung. Beim Server kommt immer alls korrekt an. Ich versuch mal zu beschreiben wie Client und Server arbeiten. - Beide arbeiten mit einer blockierenden Verbindung - Der Client sendet mit TWinSocketStream seine Daten an den Server. Nachdem der Client seine Daten versandt hat schließt er die Verbindung. - TServerSocket nimmt den Verbindungsversuch an und erstellt in OnGetThread für die Verbindung einen TServerClientThread (hier wird ein neuer Thread erzeugt !!!). Der TServerClientThread liest die Daten aus der Verbindung innerhalb von ClientExecute. Wenn alle Daten aus der Verbindung gelesen wurden können die Daten in die Datenbank geschrieben werden. Da ja jetzt alle Daten komplett da sind. Was kann passieren: Der Client sendet einen Kontakt an den Server während der Server den vorherigen Kontakt in die Datenbank schreibt. Kein Problem - TServerSocket nimmt den Verbindungsversuch an und spaltet in OnGetThread einen neuen Thread für die Verbindung ab. Ich habe mal mein Testprogramm angehängt. Über den Öffnen Button im Client kannst Du eine Textdatei in das Memo laden. Wenn Du auf Senden klickst sendet der Client zehnmal das Memo an der Server. Direkt hintereinander !!! Auf dem Server-Formular sind zwei Memos. Der Inhalt aus dem Client-Memo wird dabei abwechselnd einmal im linken und einmal im rechten Memo angezeigt. P.S. als ich noch asynchrone Verbindungen verwendet habe bin ich immer auf das gleiche Problem wie Du gestoßen. Deshalb bin dann zu den komplizierten blockierenden Verbindungen übergegangen. Asynchrone Verbindungen sind eine MS Erfindnung. Unter Unix gibt es grundsätzlich nur blockierende Verbindungen. Warum wohl? |
Re: Sehr langen String mit Clientsocket an Serversocket send
Zitat:
Code:
Was ist wenn Verzögerung > 2000 ist und nicht alle Daten angekommen sind?
until not aWSStream.WaitForData(2000)
Ach klar, der Thread läuft ja solange der Client da ist ... Aber jedes man eine neue Verbindung aufzumachen ist ja auch nicht die schnellste Lösung, gibs doch zu ;-) Zu blocked Sockets habe ich aber ehrlich gesagt selbst irgendwann gewechselt, weil das sowieso viel besser ist, solche Sachen in einem Thread zu erledigen und dann mit Messages (oder anderes) an den Main zu schmeißen. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo AnTiPrimaTe,
gemäß OH soll die Eigenschaft ClientSocket von TServerClientThread den Endpunkt auf der Serverseite mit dem Client repräsentieren. Seltsamerweise habe ich es noch nicht geschafft über ClientSocket etwas an den Client zu senden. Weißt Du wie das geht ? Bislang habe ich mir damit beholfen, dass auf dem Clientformular ebenfalls eine TServerSocketkomponente sitzt. D.h Client und Server sind austauschbar. Wenn der Client Daten sendet ist der Client der Client und der Server der Server. Wenn der Server Daten zum Client sendet ist der Server der Client und der Client der Server. Funktioniert sehr gut. Ich finde es aber ziemlich umständlich. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
sorry für Verzögerung, war viel zu tun heute ... Du muss das Lesen für den Client in einem Thread realisieren. Anbei ein kleines Beispiel, es hängt sich zwar beim Beenden auf (hatte keine Zeit/Lust nach der Ursache zu suchen, wahrscheinlich kille ich die Threads falsch) aber Daten werden in beide Richtungen versendet. Beim Connect bekommt der Client eine Message vom Server, der Client kann auch was an der Server schicken usw. |
Re: Sehr langen String mit Clientsocket an Serversocket send
Hallo,
vielen Dank. Gutes Beispiel. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:57 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