Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Dateiversand zwischen Chatclients (Indy) (https://www.delphipraxis.net/122542-dateiversand-zwischen-chatclients-indy.html)

night 17. Okt 2008 16:53


Re: Indy-TCP-Server aufsetzen und Dateien versenden
 
Dieser Beitrag stand ursprünglich in Zusammenhang mit diesem Tutorial:
Indy-TCP-Server aufsetzen und Dateien versenden



Hi,der Beitrag ist schon etwas älter, passt aber zu meinem Thema.
Hier wurde gezeigt, wie man vom Client eine Datei zum Server schicken kann. Ich möchte aber nun eine Datei von einem Client zum anderen schicken.
Ich habe mir dazu folgendes überlegt, bzw von oben übernommen:

Client:
Delphi-Quellcode:
if OpenDialog1.Execute then
    begin
      //Data= Befehl; Receiver = an wen die Datei geht und Dateiname
      Msg := '!DATA~'+receiver+'~'+OpenDialog1.FileName;
      FTCPClient.WriteLn(MSG);
      FileStream := TFileStream.Create(OpenDialog1.FileName, fmOpenRead or fmShareDenyNone);
      try
        MyFileSize := FileStream.Size;
        while MyFileSize > 0 do
        begin
          SendSize := MyFileSize;
          if SendSize > 1024 then
            SendSize := 1024;
          Dec(MyFileSize, SendSize);
        FTcpClient.WriteStream(FileStream, False, False, SendSize);
      end;
      finally
       FileStream.Free;
      end;
    end;
Der Server:
Delphi-Quellcode:
procedure TForm1.tcpServerExecute(AThread: TIdPeerThread);
var Msg: String;
    receiver: String;
    MyFileName: String;
    FileStream: TFilestream;
    list: TList;
    MyFileSize: int64;
begin
  msg := AThread.Connection.ReadLn;
  if Msg[1] = '!' then
  begin
   Msg := Trim(Copy(Msg, Pos('!', Msg) +1, Length(Msg)));
   if Trim(Copy(Msg, Pos('!', Msg) +1, Pos('~', Msg))) = 'DATA' then
   begin
    Msg := Trim(Copy(Msg, Pos('~', Msg) +1, length(Msg)));
    Receiver := Trim(Copy(Msg,1, Pos('~', Msg)));
    MyFileName := Trim(Copy(Msg, Pos('~', Msg) +1, length(Msg)));
     
    FileStream := TFileStream.Create(MyFileName, fmCreate);
    try
      AThread.Connection.ReadStream(FileStream, MyFileSize);
      List := FtcpServer.Threads.LockList;
      try
       msg := '!DATA~';
TIdPeerThread(List.Items[ListBox_Server_Clients.Items.IndexOf(Receiver)]).Connection.WriteLn(msg);     TIdPeerThread(List.Items[ListBox_Server_Clients.Items.IndexOf(Receiver)]).Connection.WriteStream(FileStream, False, False, Filestream.Size);
      finally
        FtcpServer.Threads.UnlockList;
      end;
    finally
      FileStream.Free;
    end;
   end
  end;
end;
Und dann wieder beim Clienten:
Delphi-Quellcode:
procedure TForm1.ReceiveMessage;
var Msg: String;
    command: String;
    FileStream: TFilestream;
    MyFileSize: int64;
begin
  if FTcpClient.Connected then
  begin
    if (Msg[1] = '!') then
    begin
        command := (Trim(Copy(Msg, Pos('!', Msg)+1, Pos('~', Msg) -2)));
        if command ='DATA' then
        begin
          if SaveDialog1.Execute then
          begin
            FileStream := TFileStream.Create(SaveDialog1.FileName, fmCreate);
            try
              FTCPClient.ReadStream(FileStream, MYFileSize);
            finally
              FileStream.Free;
            end;
           end;
        end;
      end
   end;
end;
Ich will damit einen bestehenden Chat, den ich letztes Jahr gemacht habe, um einen Filetranfer erweitern und habe alles Coding, das nichts damit zu tun hat rausgeschmissen(deswegen kann evt ein "end" zu viel oder zu wenig sein ;). Leider hängt sich mein Programm auf.
Ich selbst habe bis jetzt nur einfache Nachrichten verschickt (Indy 9) und befinde mich hier auf Neuland. Für Denkanstöße oder Beispiele wäre ich dankebar.

Viele Grüße
Stefan

[edit=fkerber]Thread geteilt, da eigenständige Frage. Mfg, fkerber[/edit]

hincapie 20. Okt 2008 08:47

Re: Dateiversand zwischen Chatclients (Indy)
 
Hallo,
Du musst dem Server mitteilen, wie groß die Datei ist, die da verschickt wird!
Ich habe das so gelöst:
Delphi-Quellcode:
...
  IdTcpClient1.WriteInteger(4);
  IdTcpClient1.WriteLn(sMsgToSvr);
  IdTcpClient1.WriteInteger(SendSize);
  idTCPClient1.OpenWriteBuffer;
  idTcpClient1.WriteStream(fs, False, False, SendSize);
  idTCPClient1.CloseWriteBuffer;
...
Erklärung:
In der ersten Zeile wird per Kommando dem Server mitgeteilt, was er machen sollen, ähnlich dem '!' in Deinem Code.
Danach kommt der Dateiname (sMsgToSvr), danach (wichtig!) die Dateigröße (SendSize) ...

dann der Empfang der Datei:
Delphi-Quellcode:
...
      if Msg[1] = '#' then      //send files
      begin
        msg2 := Copy(Msg, 2, Length(Msg));
        if FileExists(ProgDir + Msg2) then
          DeleteFile(ProgDir + Msg2);
        ftmpStream := TFileStream.Create(ProgDir + Msg2, fmCreate or fmShareDenyNone);
        try
          try
            //while IdTCPClient1.connected do
            FileSize := IdTCPClient1.ReadInteger();
            IdTCPClient1.ReadStream(fTmpStream, FileSize, False); //-1,true);
            Log(100, 'File ' + Msg2 + ' with ' + IntToStr(FileSize) + ' kbs received!');
            PostMessage(avatar, 'File ' + Msg2 + ' with ' + IntToStr(FileSize) + ' kbs received!');
            Application.ProcessMessages;
          except
            Log(101, 'Error on filetransfer!');
            exit;
          end;
        finally
          FreeAndNil(fTmpStream);
        end;
      end;
...
Auch hier wird erst wieder die Größe der zu empfangenden Datei festgestellt...



Ach ja, hier die Behandlung der Datei durch den Server und den Versand an alle Clients (im TCPServer.Execute):
Delphi-Quellcode:
    Cmd   := AThread.Connection.ReadInteger;
    if cmd = 4 then
    begin
      try
        try
          Msg   := AThread.Connection.ReadLn;
          FileName := Msg;
          CS := TCriticalSection.Create;
          CS.Enter;
          sMsgToClt := '#' + FileName;
          ts := TMemoryStream.Create;
          FileSize := AThread.Connection.ReadInteger();
          AThread.Connection.ReadStream(ts, FileSize, False);
          Log(Format('Getting client upload %5d, %s', [FileSize, FileName]));
          List := TcpServer.Threads.LockList;
          try
            for Count := 0 to List.Count -1 do
            try
              TIdPeerThread(List.Items[Count]).Connection.WriteLn(sMsgToClt);
              TIdPeerThread(List.Items[Count]).Connection.WriteInteger(FileSize);
              TIdPeerThread(List.Items[Count]).Connection.OpenWriteBuffer;
              TIdPeerThread(List.Items[Count]).Connection.WriteStream(ts, True, False, FileSize);
              TIdPeerThread(List.Items[Count]).Connection.CloseWriteBuffer;
              Log('File ' + ExtractFileName(FileName) + ' sent to clients!');
            except
              TIdPeerThread(List.Items[Count]).Stop;
              Log('Error while sending file to clients!');
            end;
          finally
            TcpServer.Threads.UnlockList;
            CS.Leave;
          end;
        except
          ShowMessage('Error');
          Log('Error on getting file');
        end;
      finally
        ts.free;
      end;
Edit:
Ein wenig ausführlicher habe ich das Ganze nun in folgenden Thread ausgeführt:
Beispiel zum Versenden von Dateien mit Indy


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz