Entwickler-Ecke
Internet / Netzwerk - Datei von TServerSocket zu TClientSocket senden
F.Art - Di 06.12.05 22:19
Titel: Datei von TServerSocket zu TClientSocket senden
Ich habe mich nun im Forum durchgelesen und habe keine Beispiele gefunden die ich gerafft habe.
Ich möchte eine Datei vom Server zum Client senden und direkt auf Festplatte speichern lassen. Wie geht das?
caedes - Di 06.12.05 22:32
Zunächst einmal würde ich, wenn es keine besonderen Gründe gibt, die dagegen sprechen, die indy-Komponenten empfehlen, weil man die Tserversocket und -client-kompos eigentlich nicht mehr nehmen sollte.
Um eine Datei zu behandeln, benötigst du meines Wissens einen Stream. Den kannst du dann verschicken und empfangen.
Jedoch solltest du noch einmal genauer sagen, was genau du machen willst. Um Dateien nur zu verschicken und zu speichern eignet sich wohl am allerbesten das FTP, das in den indys auch eine extra Komponente ist.
F.Art - Di 06.12.05 22:42
Mit TCP habe ich dateien transferiert bekommen.
Aber da ich ein Chatprog auf TSocket aufgebaut habe, möchte ich das nicht alles neu machen. Deswegen muss ich bei Socket bleiben.
Server:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TForm1.Button2Click(Sender: TObject); var FStream : TFileStream; begin FStream := TFileStream.Create('test.exe', fmCreate or fmShareDenyWrite); Server.Socket.SendStreamThenDrop(FStream); end; |
mehr habe ich leider nicht.
Moderiert von
raziel: Code- durch Delphi-Tags ersetzt
caedes - Mi 07.12.05 16:20
Erste Erkenntnis des Tages: Du brauchst ein Protokoll. Ich gehe einmal davon aus, dass du bisher einfach nur mit sendtext sendest und beim Empfänger mit Hilfe des Onread-Ereignisses liest, oder? Man muss sich darüber im Klaren sein, was überhaupt gesendet wird. Es ist dem TCP nämlich egal, ob es einen String oder einen Stream übergeben bekommt. Es ist lediglich eine andere Art der "Aufbewahrung" eines Inhaltes innerhalb eines Programms. Kleines Beispiel: Wenn die eine Seite eine Textdatei in einen Stream packt und diesen versendet und die andere Seite diesen mit Receivetext empfängt, wird diese es gar nicht mitbekommen, dass es sich um eine Datei handelt, sondern nur den Text anzeigen.
Du brauchst also ein Protokoll, dass dafür sorgt, dass Nachrichten im Chat von Dateien unterscheidbar sind. Ein Vorschlag:
"MESSAGE Hier dann die Nachricht" + #13 + #10 -> So könnte eine Nachrichtenübertragung aussehen (Die angehängten Rauten-Dinger sind Steuerzeichen, die anzeigen sollen, dass dies ein abgeschlossenes Paket deines eigenen Protokolls ist.)
"FILE Dateiname.xyz ......Dateiinhalt........." + #13 + #10 -> Analog dazu eine Dateiübertragung.
Außerdem solltest du darüber nachdenken, den Dateiinhalt, so wie es auch das FTP macht, auf einer zusätzlichen Verbindung zu versenden, weil, wenn es sich um eine größere Datei handelt, für die Zeit der Übertragung die Verbindung ja blockiert ist. Aber dass kann man auch später noch machen. Was erstmal wichtig ist, ist ein Protokoll und dieses im empfangenden Programm jeweils wieder zu zerpflücken.
Hoffe ich konnte dir erstmal weiterhelfen, du siehst es ist schwieriger, als man zunächst denkt, aber möglich...
Gruß caedes
F.Art - Mi 07.12.05 16:54
Stimmt, ich habe bis jetzt nur Texte mit der ersten Variante versendet.
Aber die Datei soll auch über den selben Port gesendet werden.
Nur habe ich keine Vorstellung wie ich das jetzt genau bewerkstelligen soll?
Ja-Pa - Mi 07.12.05 17:27
caedes hat folgendes geschrieben: |
Zunächst einmal würde ich, wenn es keine besonderen Gründe gibt, die dagegen sprechen, die indy-Komponenten empfehlen, weil man die Tserversocket und -client-kompos eigentlich nicht mehr nehmen sollte.
|
Was spricht denn gegen die Sockets? Sie lassen sich nicht so leicht portieren wie die Indy-Komponenten, das sehe ich ein, aber wieso sollte man sie nicht mehr verwenden?
caedes - Mi 07.12.05 17:58
Hab hier mal zusammengeschrieben, wie ich's mir denke. Muss man natürlich noch enorm was tun, ist nur ein Grundgerüst.
Sender
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| var file1: tfilestream;
procedure send_msg(msg: string); begin socket.sendtext('MSGE ' + msg); end;
procedure send_file(filename: string); begin socket.sendtext('FILE ' + filename); file1 := Tfilestream.create(filename); end;
procedure Onread; begin if socket.receivetext = 'OK' then socket.sendstream(file1); end; |
Empfänger
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var mode: integer = 0;
procedure Onread; var msg: string; begin if mode = 1 then begin file1 := socket.receivestream; mode := 0; end; else begin msg := socket.receivetext; if copy(msg,4,0) = 'MSGE' then memo1.lines.add(msg); if copy(msg,4,0) = 'FILE' then begin socket.sendtext('OK'); mode := 1; end; end; end; |
Marco D. - Mi 07.12.05 18:51
Würd mich auch mal interessieren, warum die Sockets so 'runtergemacht' werden.
Was ist denn der Nachteil an ihnen?
caedes - Mi 07.12.05 21:21
Ich hab's schon mehrfach gelesen. Habe jetzt nur einen Eintrag gefunden, in dem es von einer meiner Meinung nach ganz kompetenten Person, gesagt wird, dass die Sockets veraltet sind:
http://www.delphi-forum.de/viewtopic.php?t=27114&start=0&postdays=0&postorder=asc&highlight=sockets+veraltet
Die Begründung war in einem anderen Thread zu finden, den ich jedoch nicht mehr finde. Nur so viel: Vielleicht kann man sich darauf einigen, dass die Sockets mit Vorsicht zu genießen sind. Manche schrieben in dem Thread, dass des öfteren Pakete abhanden gekommen sein sollen usw.
Ich persönlich hab ja nichts gegen die Sockets. Ich benutze sie ja auch gern, weil man sehr viel lernt, wenn man sich selbst in diverse Protokolle einarbeitet und nicht eine x-beliebige Komponente nimmt, von der man nicht weiß wie sie funktioniert.
In diesem Sinne: Foltert mich nicht gleich für meine Aussage....
F.Art - Mi 07.12.05 21:38
Ich bekomme das mit dem Senden einfach nicht hin.
Habe verschiedene Threats gelesen und ausprobiert aber nichts.
Hat nicht einer ein ganz simplen Source, wo vom Server zu Client eine Datei gesendet wird?
Marco D. - Mi 07.12.05 21:52
@ F.ART:
Ich habe es geschafft, allerdings mit TCP Server und Client. Nicht mit den Sockets. Soll ich den Code mal posten, oder müssen es die Sockets sein?
F.Art - Mi 07.12.05 22:14
Mit TCP habe ich es auch gepackt.
Leider muss es Socket sein, da ich das Programm nicht neu coden will.
caedes - Mi 07.12.05 22:56
Habs hinbekommen mit den Sockets eine Datei zu versenden. Das Programm ist im Anhang. Ich hab das Programm auf Port 21 gestellt. Wenn ihr z.b. FilleZillaServer nehmt, wird euch alles was gesendet wird, im Hauptfenster angezeigt (Zweckentfremdung). Die gesendete Datei ist eine Textdatei und wie ihr sehen werdet wird nur der Inhalt der Datei versendet. Um Dateinahmen und alles andere muss man sich bei den Sockets selbst kümmern.
caedes - Do 08.12.05 00:29
Wo ich nochmal von Protokoll sprach bzw. die Kennzeichnung der Beendigung von Blöcken sprach. Jetzt habt ihr das Problem. Ihr müsst nämlich nicht nur einmal receive ausführen, sondern so lange bis der Puffer leer ist, bzw. erwähntes Endzeichen kommt. Das wird auch in diesem Forum diskutiert:
http://www.softgames.de/forum/viewtopic.php?t=86669&sid=617f9747f32e7c49ede7b150c410dd28
P.S.:Zu meiner Behauptung, dass die Sockets mit Vorsicht zu genießen sind: "Und genau daher muss man beachten, das es immer wieder vorkommen kann, das die Daten nicht 1:1 wieder ankommen wie sie losgeschickt wurden."
Muetze1 - Fr 09.12.05 00:45
Der 1. Link ist Müll, da er nur die Instanzenadresse verschickt aber nicht die Bilddaten selber.
Der 2. Link ist auch Müll, da dieser auch die mehrfachen OnClientReads nicht beachtet.
Der Link auf Softgames mit den alten Beiträgen von mir sollten dir eigentlich alle Hinweise dazu geben das zu lösen: Du musst immer schauen wieviel du von der Grösse der Datei schon empfangen hast. Wenn es noch nicht alles ist, dann weiter in die Datei schreiben. Das OnClientRead kann halt x-mal mit unterschiedlich grossen Blöcken aufgerufen werden, bis du die Datei zusammen hast und z.T. natürlich mehr Daten die schon wieder nach der Datei folgen.
F.Art - Fr 09.12.05 01:04
procedure TForm1.Button2Click(Sender: TObject);
Var
Stream : TFileStream;
SSize : Integer;
Begin
Stream := TFileStream.Create('test.exe', fmCreate or fmShareDenyWrite);
SSize := Stream.Size;
Server.Socket.WriteBuffer(SSize, SizeOf(SSize));
Server.Socket.SendStream(Stream);
End;
Irgendwie mach ich immer noch was falsch.
Muetze1 - Fr 09.12.05 01:13
F.Art hat folgendes geschrieben: |
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm1.Button2Click(Sender: TObject); Var Stream : TFileStream; SSize : Integer; Begin Stream := TFileStream.Create('test.exe', fmCreate or fmShareDenyWrite); SSize := Stream.Size; Server.Socket.WriteBuffer(SSize, SizeOf(SSize)); Server.Socket.SendStream(Stream); End; |
Irgendwie mach ich immer noch was falsch. |
Nutze bitte die Delphi-Tags für deine Quellen und zum anderen liegt der Fehler wohl darin, dass du die EXE mit fmCreate aufrufst und sie dann versenden willst. fmCreate legt die Datei aber neu an, wenn sie nicht vorhanden ist und überschreibt sie sonst. Daher solltest du sie nicht lieber zum Lesen öffnen (fmOpenRead)??
F.Art - Fr 09.12.05 01:27
Die Tagsbuttons werden bei mir nicht angezeigt.
Habe trotzedem folgenden fehler
[Fehler] Unit1.pas(36): Undefinierter Bezeichner: 'WriteBuffer'
Muetze1 - Fr 09.12.05 10:50
1. Was sind "Tagsbuttons" ??
2. Mit der Fehlermeldung kann man doch schonmal was anfangen.
3. Die Komponente Server ist ein TServerSocket? Wenn das richtig ist, dann kann dieser natürlich haufenweise Clients haben die mit ihm verbunden sind. Du musst nun natürlich sagen, welches Client du was schicken willst. Dazu hast du beim ServerSocket unter Server.Socket. zum einen die Eigenschaft "ActiveConnections" mit der Anzahl der verbundenen Clients und zum anderen eine Array-Eigenschaft "Connection[]" auf die du per Index zugreifen kannst. Dabei steht der Index für eine Verbindung zu einem Client und liegt immer zwischen 0 und ActiveConnections-1.
Du hast soviele vollständige Delphi Versionen, somit nutze die beiliegende Hilfe. Das ist alles auch darin beschrieben und verlinkt und man kommt auf einfachste Weise von dem Hilfeeintrag "TServerSocket" zu den gewünschten Eigenschaften und Informationen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!