![]() |
indy10 / TCPServer /TCPClient ->Datei versenden
hi Leuts
Ich mach grad n kleines Testprogramm. Ich möchte eine Datei vom einen zum anderen Client verschicken, übers Netzwerk mit Progressbaranzeige auf beiden seiten! Habe leider aber nach langer Suche immer noch nichts dazu gefunden, weder hier im Forum noch auf google. Vielleicht kennt ja jmd von euch ein brauchbares Tutorial! Liebe Grüsse |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Hi Kaktus und Danke vielmals.
Bin den Code soeben am testen, aber ich stelle leider fest, dass wenn ich die variable
Delphi-Quellcode:
deklarieren will, der Typ TIdStreamVCL NICHT gefunden wird obwohl ich das
IDS: TidStreamVCL;
Delphi-Quellcode:
drin habe!
uses IdStreamVCL;
Jmd eine Idee? |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
suche einmal nach der Datei "idStreamVCL.pas", wenn es sie auf deinem Rechner nicht gibt, dann weißt du es
oder du hast die Datei nicht in den Suchpfad eingefügt |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
daran liegts eben nicht. die Datei ist vorhanden und BDS findet sie auch. in den uses habe ich sie angegeben und dort wird sie auch erkannt! (nicht rot unterstrichen) aber es scheint, als sei dieser Typ (TIdStreamVCL) gar nicht vorhanden dort?!
Die Datei liegt in C:\Programme\BDS\4.0\Indy10\System Der gesamte Inhalt der Datei:
Delphi-Quellcode:
Da seh ich nichts von TIdStreamVCL!
{
$Project$ $Workfile$ $Revision$ $DateUTC$ $Id$ This file is part of the Indy (Internet Direct) project, and is offered under the dual-licensing agreement described on the Indy website. ([url]http://www.indyproject.org/[/url]) Copyright: (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved. } { $Log$ } unit IdStreamVCL; interface {$I IdCompilerDefines.inc} uses Classes, IdGlobal; type TIdStreamHelperVCL = class public class function ReadBytes( const AStream: TStream; var VBytes: TIdBytes; const ACount: Integer = -1; const AOffset: Integer = 0) : Integer; {$IFDEF DOTNET} static; {$ENDIF} class procedure Write( const AStream: TStream; const ABytes: TIdBytes; const ACount: Integer = -1); {$IFDEF DOTNET} static; {$ENDIF} end; implementation class function TIdStreamHelperVCL.ReadBytes(const AStream: TStream; var VBytes: TIdBytes; const ACount, AOffset: Integer): Integer; var aActual:Integer; begin Assert(AStream<>nil); Result:=0; if VBytes = nil then begin SetLength(VBytes, 0); end; //check that offset<length(buffer)? offset+count? //is there a need for this to be called with an offset into a nil buffer? aActual:=ACount; if aActual = -1 then begin aActual := AStream.Size - AStream.Position; end; //this prevents eg reading 0 bytes at Offset=10 from allocating memory if aActual=0 then begin Exit; end; if Length(VBytes) < (AOffset+aActual) then begin SetLength(VBytes, AOffset+aActual); end; Assert(VBytes<>nil); Result := AStream.Read(VBytes[AOffset], aActual); end; class procedure TIdStreamHelperVCL.Write(const AStream: TStream;const ABytes: TIdBytes; const ACount: Integer); var aActual:Integer; begin Assert(AStream<>nil); aActual:=ACount; //should we raise assert instead of this nil check? if ABytes <> nil then begin if aActual = -1 then begin aActual := Length(ABytes); end else begin aActual := Min(aActual, Length(ABytes)); end; if aActual > 0 then begin AStream.Write(ABytes[0], aActual); end; end; end; end. Wenn ich diesen Typ: TIdStreamHelperVCL verwende, kann ich im Konstruktor aber keinen TFileStream angeben! so sollte es sein:
Delphi-Quellcode:
das kann ich nur:
TidStreamVCL.Create(FStream);
Delphi-Quellcode:
aber das bringt mir nichts!
TidStreamHelperVCL.Create
Ideeen? |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
füge einmal "IdGlobal" in die Uses Liste ein ;)
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
das hab ich auch schon versucht. Leider kein Erfolg!
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
@TidStreamVCL
es ist ja keine visuelle Komponente, daher kannst du davon auch nichts sehen (da auch kein Registryeintrag da ist kann es auch unmöglich eine Komponente sein) |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Hä? Wie meinste das jetz?! mir ist bewusst das dies keine visuelle Komponente ist. Tatsache ist aber, dass es den Typ (TidStreamVCL) nicht gibt bei mir?!
Fehler beim versuch das Programm zu compilieren:
Delphi-Quellcode:
[Pascal Fehler] main.pas(39): E2003 Undefinierter Bezeichner: 'TidStreamVCL'
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
schau dir einmal den Thread
![]() |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Ok, Ist zwar jetz nicht DIE Lösung, sondern eine Umgehung des Problems. Aber trotzdem, wie geht das jetzt mit der Progressbar? ;-)
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Delphi-Quellcode:
progressbar.min := 0;
try //Anweisungen progressbar.Position:= 100; finally |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
ich verweise auf meinen Tip im Beitrag #2 dieses Threads. Da steht alles beschrieben zwecks Progressbar beim Filetransfer. :coder2:
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
hey... ich habs jetzt mal so gemacht. Es funktioniert allerdings nicht immer und nicht zuverlässig.
Was ich jetzt will ist: Der Client soll eine Datei an den Server schicken können aber vorab soll der name der zu schickenden Datei gesendet werden, damit dann der Server die Datei unter diesem Namen abspeichern kann. Dies hab ich mal probiert zu machen aber ich halte den Code für naja, unschön ist noch milde ausgedrückt. Kurz: Wie kann ich verschiedene Sachen (Strings für Befehle, Anfragen und Meldungen und die Streams) kommunizieren ohne das es mir ein Durcheinander gibt? Ich kann ja nie wissen was ich gerade erhalten habe? Mein momentaner CodeSalat:
Delphi-Quellcode:
procedure TForm1.EButton2Click(Sender: TObject);
var FStream: TFileStream; begin try if OpenDialog1.Execute then begin if FileExists(OpenDialog1.FileName) then begin FStream := TFileStream.Create(OpenDialog1.FileName, fmOpenRead); TCPClient.Connect; TCPClient.IOHandler.WriteLn(ExtractName(Opendialog1.FileName)); TCPClient.Disconnect; TCPClient.Connect; try TCPClient.IOHandler.Write(Fstream,0,true); finally FreeAndNil(FStream); end; if TCPClient.Connected then TCPClient.Disconnect; end else MessageDlg('file does not exist!', mtError, [mbOK], 0); end; except on e:Exception do MessageDlg(e.Message, mtError, [mbOK], 0); end; end; // TCP Server procedure TForm1.TCPServerExecute(AContext: TIdContext); var FSTream: TFileStream; df: String; begin try if savefilepath = '' then begin savefilepath := DestinationEdit.Text+AContext.connection.IOHandler.ReadLn ; Memo1.Lines.Add('download file: "'+savefilepath+'" from '+AContext.Binding.PeerIP); end else begin try if FileExists(savefilepath) then begin if MessageDlg('overwrite existing file?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin df := savefilepath; DeleteFile(df); FStream := TFileStream.Create(savefilepath, fmCreate); AContext.connection.IOHandler.ReadStream(fstream); end; end else begin if DirectoryExists(ExtractFilePath(savefilepath)) = false then CreateDir(ExtractFilePath(savefilepath)); FStream := TFileStream.Create(savefilepath, fmCreate); AContext.connection.IOHandler.ReadStream(fstream); end; finally FreeAndNil(FStream); end; AContext.connection.Disconnect; end; savefilepath := ''; except on e:Exception do MessageDlg(e.Message, mtError, [mbOK], 0); end; end; |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Liste der Anhänge anzeigen (Anzahl: 3)
hey leuts
ich habe nun mein testprogramm fertiggestellt, es hat aber noch einen Fehler! und ich finde ihn nicht heraus! bin schon seit stunden dran und mir gehen langsam die ideeen aus. Manche Dateien kann ich übertragen andere nicht, manchmal geht diese und manchmal aber nur die andere. Vielleicht schauts mal jmd von euch an?! wär echt toll! ![]() Danke schon mal zum Voraus Liebe Grüsse Cherry |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Hi,
ich hab mir bis jetzt zwar nur Deinen "Codesalat" hier angeschaut, aber was Du brauchst ist definitiv eine saubere Serverstruktur und ein kleines eigenes Protokoll. - Du solltest vor dem Stream ein Text Commando zum Server schicken mit allen für den Transfer nötigen Information z.B. FILETRANSFER||AUTOEXEC.BAT||348||OVERRIDEONSERVER - Dann solltest Du auf jeden Fall Informationen zu dem jeweiligen Client in AContext.Data abspeichern; ich benutze dazu oft folgendes :
Delphi-Quellcode:
Für die unterschiedlichen Projekte erstelle ich mir dann immer eine Klasse TClientData,
unit JFIndy10BaseClientData;
// copyright by DataCool (at) gmx dot net // in case of modifications please let me know interface uses IdContext; Const // predefined Status numbers cCSUnknown : Byte = 0; cCSJustConnected : Byte = 1; cCSGoing2Disconnect : Byte = 2; cCSDisconnected : Byte = 3; cCSWaiting4NextCmd : Byte = 4; // status after a noop cmd type TIndyBaseClientData = class private // is a login necessary for this connection //fLoginRequired : Boolean; // login was successfull //fLoginOK : Boolean; // is a NOOP Command for this connection required ? fNoopRequired : Boolean; // Last-Command fLastCmd : String; // Last-Command as Integer, in case the server is working with integer commands fLastIntCmd : Word; // Last command time, necessary together with noops to detect dead client connections fLastCmdTime : TDateTime; // time of the connect of this connection fTimeOfConnect : TDateTime; // Status of this connection, maybe later on switch to type word, if a program requires more than 255 commands fStatus : Byte; // Indy-Context of this connection fContext : TIdContext; // procedures to set the last command,lastCmdTimd would be updated also procedure setStrCommand(Const Cmd : String); procedure setIntCommand(Const Cmd : Word); protected public Constructor Create(AContext : TIdContext); property Context : TIdContext read fContext; //property LoginRequired : boolean read fLoginRequired write fLoginRequired; //property LoginOk : boolean read fLoginOk write fLoginOk; property NoopRequired : Boolean read fNoopRequired write fNoopRequired; property LastCmd : String read fLastCmd write setStrCommand; property LastIntCmd : Word read fLastIntCmd write setIntCommand; property LastCmdTime : TDateTime read fLastCmdTime write fLastCmdTime; property TimeOfConnect : TDateTime read fTimeOfConnect write fTimeOfConnect; property Status : Byte read fStatus write fStatus; // isConnectionDead ? end; implementation uses SysUtils; { TIndyBaseClientData } constructor TIndyBaseClientData.Create(AContext: TIdContext); begin inherited Create; fContext := AContext; //fLoginRequired := true; //fLoginOK := false; fNoopRequired := false; fLastCmd := ''; fLastIntCmd := 0; fLastCmdTime := 0; fTimeOfConnect := now; fStatus := cCSUnknown; end; procedure TIndyBaseClientData.setIntCommand(const Cmd: Word); begin // dont compare cmd and fLastIntcommand, because perhaps the same cmd is coming 2 times fLastIntCmd := Cmd; fLastCmd := InttoStr(fLastIntCmd); // update also the last command time fLastCmdTime := now; end; procedure TIndyBaseClientData.setStrCommand(const Cmd: String); begin // dont compare cmd and fLastcommand, because perhaps the same cmd is coming 2 times fLastCmd := Cmd; fLastIntCmd := StrToIntDef(fLastCmd,0); // update also the last command time fLastCmdTime := now; end; end. die von der oben genannten Klasse erbt/abgeleitet wird. Im OnConnect des Servers erzeuge ich dann meine Klasse TClientData, fülle diese mit Daten/Infos und lege Sie in AContext.Data ab. Im OnExecute des Servers:
Delphi-Quellcode:
- Wichtig ! Im OnDisconnect müssen die Daten des Clients auch wieder freigegeben werden
Var sUppCmd : String;
sRawCmd : String; iPos : Longint; sParam : String; tmpClient : TClientData; begin // Prüfen, ob Client Daten vorhanden sind // bei Indy10 wird das OnExecute auch einmalig ausgeführt, wenn die Connection des Clients im OnConnect getrennt wurde if not assigned(AThread.Data) then begin AContext.Connection.Disconnect; exit; end; // Client-Daten zu auslesen try tmpClient := TClientData(AThread.Data); except AContext.Connection.Disconnect; exit; end; if (tmpClient.Status = cCSGoing2Disconnect) or (tmpClient.Status = cCSDisconnected) then begin AContext.Connection.Disconnect; exit; end; try // Daten im Buffer ? tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,Settings.CmdReadTimeOut,Settings.CmdMaxLength); except tmpClient.LastCmd := ''; end; // Da das OnExecute des Server immer wieder eintritt bis der Client nicht mehr verbunden ist kann der obere Teil als // allgemeingültig bezeichnet werden. Je nach empfangenen Daten/Kommando jetzt weiter vorgehen // z.B. Case tmpClient.LastIntCommand of // end; // oder if tmpClient.LastCmd = 'YXZ' then begin end; // ...
Delphi-Quellcode:
Ich hoffe ^das^ hat erstal ein groben Überblick/Denkanstoss geschaffen,
Var tmpClient : TClientData;
begin // valid data in . data if Assigned(AContext.Data) then begin // try to cast the data to TClientData try tmpClient := TClientData(AContext.Data); except tmpClient := Nil; end; // Cast successfull ? if Assigned(tmpClient) then FreeAndNil(tmpClient) // !!!! very imported to set AContext.Data to nil !!!!! AContext.Data := Nil; end; end; wie man sowas realisieren könnte. Außerdem sollte im Servercode kein MessageDlg verwendet werden, ein Server sollte selbstständig und OHNE Interaktion mit dem User laufen. Am besten sogar ganz ohne GUI als Dienst. Greetz DataCool |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Liste der Anhänge anzeigen (Anzahl: 1)
mit der Grafik musst du dir noch was einfallen lassen, beim 20 Zoll sieht das so aus:
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
![]() Mann ist die Indyhilfe bescheiden...irgendwann erscheint der Button Home auf dem Link und dann eine Suchleiste,darin findet man z.B. idStream.write und dort sieht man dann die benötigte Unit. Topic Path: Symbol Reference > Types > TIdStream Type ContentsIndexHome PreviousUpNext TIdStream Type Collapse All Implements a stream wrapper for the platforms supported by the Indy library. File IdObjs Pascal TIdStream = TStream; Description TIdStream is a TObject descendant that specifies a wrapper for stream classes. TIdStream isolates the differences between stream implementations for the platforms supported by the Indy library. To minimize the number of overloaded methods required for TStream and .Net Stream arguments, TIdStream provides an implict converter as a class operator for VCL to .Net stream types. TIdStream overrides provides methods used for reading and writing to the stream that isolate the differences between pointers and memory allocation for the .Net platform. See Also TIdBytes Copyright © 1993-2006, Chad Z. Hower (aka Kudzu) and the Indy Pit Crew. All rights reserved. Post feedback to the Indy Docs Newsgroup. Uses idObjs; //ist ja auch völlig logisch, lol,ob die wohl Drogen konsumieren? |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Zitat:
Ich hab mir also mal deine Unit "JFIndy10BaseClientData" nachgebaut und versucht zu implementieren. Dabei bin ich gleich auf ein Problem(chen) gestossen. Und zwar im OnExecute Event vom Servercode:
Delphi-Quellcode:
Ich denke da hast du noch was von einer älteren Indy-version vermischt. Habe einfach "AThread.Data" in "AContext.Data" geändert. Aber jetzt das eigentliche Problem(chen):
// Client-Daten zu auslesen
try tmpClient := TClientData(AThread.Data); except AContext.Connection.Disconnect; exit; end;
Delphi-Quellcode:
Ich kann nicht auf "Settings" zugreiffen (Nicht def. Bezeichner)... woher genau soll das kommen? hab ich was verpasst?
try
// Daten im Buffer ? tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,Settings.CmdReadTimeOut,Settings.CmdMaxLength); except tmpClient.LastCmd := ''; end; Ansonsten finde ich den Ansatzt sehr gut und hoffe den so implementieren zu können das alles nach meinen Vorstellungen klappt. Noch was, wieso soll das Ganze am besten ohne GUI und noch besser als Dienst laufen?! Wenn ich ein anständiges exception handling mache sollte das doch kein Problem sein?! Nun noch eine Frage zum Senden der Datei Kann ich das jetzt so machen:
Delphi-Quellcode:
oder muss ich den Stream umwandeln? Wenn ja wie und in was? vielleicht so?:
FStream := TFileStream.Create(uploadfilepath, fmOpenRead or fmShareDenyWrite);
TCPClient.Connect; try TCPClient.IOHandler.Write(Fstream,0,true); finally FreeAndNil(FStream); end;
Delphi-Quellcode:
Naja ich dank euch schon mal allen für die tolle Hilfe...
// Send TCP Stream
procedure TForm1.TCPSendStream(Stream: TFileStream); var IdStream: TIdStream; begin IdStream:= TIdStream.Create; IdStream.CopyFrom(Stream,SizeOf(Stream)); TCPClient.Connect; TCPClient.IOHandler.Write(IdStream,0,true); TCPClient.Disconnect; end; wär genial wenn ihr mich noch ein bisschen begleiten würdet, bis ich dann auf eigenen Füssen stehen kann... hehe :cheers: |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Hi Cherry,
Du hast recht ich habe ^den^ Source mal eben von Indy9 auf Indy10 portiert, damit Du was damit anfangen kannst. Hier eben die kleinen Portierbugs behoben:
Delphi-Quellcode:
// Client-Daten zu auslesen
try tmpClient := TClientData(AContext.Data); except AContext.Connection.Disconnect; exit; end;
Delphi-Quellcode:
Zum Senden einer Datei via Stream; Ich kann Dir jetzt nicht mit 100% Sicherheit sagen wie's gemacht wird,
try
// Settings.CmdReadTimeOut <-- meine Einstellungsklasse der WErt des ReadlnTimeOutsfür Kommandos // Settings.CmdMaxLength <-- meine Einstellungsklasse der Wert der maximalen Zeichenlänge mein ReadLn // Daten im Buffer ? 5000 ms = 5 Sekunden ReadLn-Timeout, maximal 1024 lesen // die Parameter beim ReadLn sind optional und müssen nicht zwingend verwendet werden tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,5000,1024); except tmpClient.LastCmd := ''; end; weil ich meine akztuellen Projekte alle noch in Indy9 habe und bald erst mit dem portieren anfange. Was ich aber festgestellt habe ist das es in Indy10 kein "WriteStream" mehr gibt, obwohl ein "ReadStream" gibt. Ich habe aber auch gesehen das es bei Indy10 jetzt ein WriteFile gibt und wenn man sich den Source dazu anschaut :
Delphi-Quellcode:
^^ Da könntest Du Dir die Vorgehensweise abschauen.
function TIdIOHandler.WriteFile(const AFile: String; AEnableTransferFile: Boolean): Int64;
var //TODO: There is a way in linux to dump a file to a socket as well. use it. LStream: TIdStream; begin EIdFileNotFound.IfFalse(Sys.FileExists(AFile), Sys.Format(RSFileNotFound, [AFile])); LStream := TReadFileExclusiveStream.Create(AFile); try Write(LStream); Result := LStream.Size; finally Sys.FreeAndNil(LStream); end; end; Jetzt nochmal zu der Frage warum ich keine GUI verwenden würde : Wenn es nachher ein produktiver Server ist, soll er vor allem eins : Laufen ohne abzustürzen ;-) Eine hohe Ausfallsicherheit erreichst man unter anderem auch, indem man die Fehlerquellen minimiert, wenn Du mit einer GUI in einem Multi-Threaded Server arbeitest, solltest alle Änderungen an der GUI nur syncronisiert vorgenommen werden, ansonsten könne recht "unschöne" Sachen passieren und Du denkst Dein Server läuft noch obwohl er nicht mehr richtig arbeitet. Klar kannst Du, wenn Du sauber programmierst das ganze auch mit GUI machen, ich wollte Dich nur auf die Gefahren hinweisen ;-) Versteh mich nicht falsch ich habe zu meinen "Servern" auch eine GUI aber das ganze läuft bei mir so : - Server wird als Dienst geschrieben, hat keine Gui und keine Interaktion mit dem Desktop - Im Server wird ein zusätzlicher Port nur lokal geöffnet - Dann schreibe ich meine "GUI zum Server" als eigene Anwendung, die dann über den lokalen Port sich die Infos die sie braucht holt und anzeigt. - die lokale Kommunikation zwischen Server-GUI und Server-Dienst ist natürlich verschlüsselt und die GUI muss sich natürlich erst beim connecten verifizieren. ^^ Aber das must Du jetzt nicht alles machen, man muss ja auch nicht mit Kanonen auf Spatzen schiessen ;-) Alles nur Denkanstösse, Greetz DataCool |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Ich weiß nicht, ob es in diesem Fall nützlich ist, aber vor einiger Zeit habe ich mich mal ans Senden per TCP und Indy 10 gemacht, und dazu auch was für die CodeLib aufbereitet. Du findest den Code
![]() |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Danke für deine schnelle Antwort...
... und wieder sind mir einige Lichter aufgegangen... habe aber leider immer noch div. Probleme... Also, was ich will ist erstmal folgendes... - Programm#1 will Programm#2 eine Datei schicken. Und sendet (cmd 1) an Prg#2 - Programm#2 erhält den Command 1 (jmd will datei senden) - Programm#2 akzeptiert (cmd 2) oder lehnt Datei ab (cmd 3) - Programm#1 wenn Prg#1 (cmd 2) erhält versucht es Datei an Prg#2 zu senden. Wenn (cmd 3) dann abbrechen. Dabei ist Programm#1 und Programm#2 genau dasselbe... läuft einfach auf unterschiedlichen Rechnern... Die Programm sollen die Informationen so austauschen, dass das andere immer weiss was das andere macht. Wenn ich das jetzt so mache wie du mir vorschlägst:
Delphi-Quellcode:
Dann überschreibts ja immer gleich tmpClient.LastCmd...
.. try
// Daten im Buffer ? tmpClient.LastCmd := AContext.Connection.Socket.ReadLn(#$A,Settings.CmdReadTimeOut,Settings.CmdMaxLength); except tmpClient.LastCmd := ''; end; // Da das OnExecute des Server immer wieder eintritt bis der Client nicht mehr verbunden ist kann der obere Teil als // allgemeingültig bezeichnet werden. Je nach empfangenen Daten/Kommando jetzt weiter vorgehen // z.B. Case tmpClient.LastIntCommand of // end; // oder if tmpClient.LastCmd = 'YXZ' then begin end; // ... Wie kann ich nun z.B. den Namen der Datei schicken?! usw. Es müsste ja irgendwie möglich sein zuerst einen befehl zu schicken und dann noch weitere Parameter z.b. Filename... oder dann beim uploaden den befehl z.b (cmd 2) für upload und dann den stream... Irgendwo hab ich noch ne grosse lücke! Gruss |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Allen vielen Dank für eure Hilfe...
Fürs erste hab ichs nun hinbekommen, scheint jedenfalls zu funktionieren. Eine kleine Frage hätte ich da aber noch, wie kann man nun die Progressbar des "uploaders" (TCPServer) anzeigen lassen? hier mein aktueller code:
Delphi-Quellcode:
und
// SEND FILE / ACCEPT INCOMMING FILE (same button)
procedure TForm1.EButton2Click(Sender: TObject); begin if EButton2.Caption = 'upload' then begin if OpenDialog1.Execute then begin try uploadfilepath := OpenDialog1.FileName; EButton2.Enabled := False; EButton5.Enabled := False; TCPClient.Connect; // upload file TCPSendCmd(CmdUploadFile); TCPClient.IOHandler.WriteLn(ExtractName(uploadfilepath)); Log(msg001); Log('wait for client reply...'); except on e:Exception do begin Log(e.Message); EButton2.Enabled := True; end; end; end; end else begin try ButtonCaption('receive'); EButton2.Enabled := False; EButton4.Enabled := False; EButton5.Enabled := False; TCPClient.Connect; // accept file TCPSendCmd(CmdRecFileOK); except on e:Exception do Log(e.Message); end; end; end;
Delphi-Quellcode:
hehe
procedure TForm1.TCPServerExecute(AContext: TIdContext);
var FSTream: TFileStream; df: String; tmpClientData : TClientData; begin if not assigned(AContext.Data) then begin AContext.Connection.Disconnect; exit; end; // read clientdata try tmpClientData := TClientData(AContext.Data); except AContext.Connection.Disconnect; exit; end; // check state if (tmpClientData.Status = cCSGoing2Disconnect) or (tmpClientData.Status = cCSDisconnected) then begin AContext.Connection.Disconnect; exit; end; // get command try tmpClientData.LastCmd := AContext.Connection.Socket.ReadLn(#$A,5000,1024); except tmpClientData.LastCmd := ''; end; // check the old command case tmpClientData.LastIntCmd of // GUY WANTS TO SEND FILE 1: begin savefilepath := DestinationEdit.Text + AContext.Connection.IOHandler.ReadLn; Log(AContext.Binding.PeerIP+' wants to send file: "'+ExtractName(savefilepath)+'"'); ButtonCaption('receive'); EButton4.Enabled := True; end; // UPLOAD FILE 2: begin Log('upload file...'); TCPSendCmd(4); try // upload FStream := TFileStream.Create(uploadfilepath, fmOpenRead or fmShareDenyWrite); TCPClient.IOHandler.Write(FStream,0,true); // disconnect AContext.Connection.Disconnect; if TCPClient.Connected then TCPClient.Disconnect; tmpClientData.Status := cCSDisconnected; finally FStream.Free; end; Log('successfully uploaded'); ButtonCaption('upload'); EButton4.Enabled := False; EButton2.Enabled := True; EButton5.Enabled := True; end; // GUY REFUSED FILE 3: begin Log('guy refused to download file'); // disconnect AContext.Connection.Disconnect; if TCPClient.Connected then TCPClient.Disconnect; tmpClientData.Status := cCSDisconnected; ButtonCaption('upload'); EButton4.Enabled := False; EButton2.Enabled := True; EButton5.Enabled := True; end; // DOWNLOAD FILE 4: begin try if FileExists(savefilepath) then begin Log('file was already existing'); df := savefilepath; DeleteFile(df); Log('old file deleted!'); end else if DirectoryExists(ExtractFilePath(savefilepath)) = false then begin CreateDir(ExtractFilePath(savefilepath)); Log('directory "'+ExtractFilePath(savefilepath)+'" created'); end; Log('download...'); try // download FStream := TFileStream.Create(savefilepath, fmCreate); AContext.connection.IOHandler.ReadStream(fstream); // disconnect AContext.Connection.Disconnect; if TCPClient.Connected then TCPClient.Disconnect; tmpClientData.Status := cCSDisconnected; finally FStream.Free; end; Log('file successfully downloaded!'); ButtonCaption('upload'); EButton4.Enabled := False; EButton2.Enabled := True; EButton5.Enabled := True; except on e:Exception do Log(e.Message); end; end; // RECEIVE CHAT MESSAGE 5: begin Log(AContext.Binding.PeerIP+': '+AContext.Connection.IOHandler.ReadLn); AContext.Connection.Disconnect; end; end; end;
Delphi-Quellcode:
procedure TForm1.TCPSendCmd(Cmd: Byte);
begin try TCPClient.IOHandler.WriteLn(IntToStr(Cmd)); except on e:Exception do Log(e.Message); end; end; |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Hi,
so jetzt frage ich doch nochmal... Was ich will: Ich will ein TJpegImage oder TBitmap in einen Stream speichern und dann den Stream über TCPClient an den TCPServer senden. (Höhrt sich einfach an, treibt mich aber noch in den Wahnsinn) Das schlimme dabei ist, ich benutze Indy 10 und da gibt es keinen 'WriteStream'! :roll: Wie ich es bisher umgangen hab: Ich hab das JPG in eine Datei gespeichert und die Datei dann versendet, empfangen, geladen, gelöscht und das funktioniert auch perfekt nur ist es halt regelrecht lahm aufgrund der vielen Festplattenzugriffe. Bisher hab ich folgendes:
Delphi-Quellcode:
Bei der Filesize weiß ich, das sie den richtigen Wert enthält.
// Client sendet den Stream
memStream := TMemoryStream.Create; jpgTmp.SaveToStream(memStream); memStream.Position := 0; FClient.IOHandler.Write(memStream); // Server epfängt den Stream memStream := TMemoryStream.Create; AContext.Connection.IOHandler.ReadStream(memStream,FileSize); memStream.Position := 0; jpgTmp.LoadFromStream(memStream); Wenn ich aber das Debug hängt der Client in 'Write' und der server in 'ReadStream' und weiter gehts nicht mehr. :gruebel: Oder habe ich eventuell jetzt schon einen Fehler gemacht? :pale: Zitat:
Ich hoffe irgendwer hat eine Lösung parat bzw kann mir helfen, dass ich den Stream versendet und empfangen bekomm. Danke schonmal! |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
schau dir bitte den Beitrag von ManuMF #21 an, das wird bestimmt helfen
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Zitat:
Die Unit 'IdStreamVCL' enthält bei mir keinen Typ 'TidStreamVCL' sondern nur 'TIdStreamHelperVCL'. (Welcher nichtmal einen Parameter im Create hat) |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
schau dir den Beitrag #10 an
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
Mit dem Post wolltest du wahrscheinlich auf
![]() Das ist aber genau der murks den ich momentan mache. (wie bereits erwähnt) Da werden keine Daten direkt versendet per Stream, da wird erst in eine Datei gespeichert, die Datei wird versendet und beim Empfänger gespeichert, Beim empfänger wird die Datei geladen und dann erst hat man den Stream/Inhalt. Das ganze hin und hergespeichere kann man sich doch bestimmt ersparen indem man direkt einen Stream versendet, nur wie? :cry: Naja ich hau jetzt Indy 10 raus und Indy 9 rein. Dann hab ich auch mein 'WriteStream' und die Welt ist heile... :thumb: (hoffentlich^^) Danke trotzdem! |
Re: indy10 / TCPServer /TCPClient ->Datei versenden
für Indy 9 wirst du im Delphitreff forum viel finden
|
Re: indy10 / TCPServer /TCPClient ->Datei versenden
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 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 by Thomas Breitkreuz