Einzelnen Beitrag anzeigen

Benutzerbild von hincapie
hincapie

Registriert seit: 24. Mär 2005
200 Beiträge
 
Delphi 5 Professional
 
#53

Re: Beispiel zum Versenden von Dateien mit Indy

  Alt 20. Okt 2008, 09:09
Zitat von hincapie:
Bin noch nicht entscheidend weiter gekommen:
Nochmal meine Frage:
Wie bringe ich den Server dazu, die empfangenen Dateien an alle Clients weiterzuverteilen?
Ich zitiere mich ausnahmsweise mal selber, da ich zu dieser Frage inzwischen eine Antwort gefunden habe, die ich teilweise schon in diesem Thread beschrieben habe: http://www.delphipraxis.net/internal...=954701#954701

Also, hier nochmal ausführlich, mit Indy 9 erstellt und getestet:

Ich drücke auf einen Button, um eine Datei zu versenden:
Delphi-Quellcode:
procedure TForm1.FileButtonClick(Sender: TObject);
Var
  fs : TFileStream; // Zum Lesen der Datei
  iTmpSize : Longint; // Zähler um sich zu merken, wieviel Bytes schon gebuffert/gesendet wurden wurden
  SendSize,
  SendSize1 : Longint; // Byte-Anzahl die gelesen werden sollen
  bError : Boolean; // Bool-Schalter für Fehlererkennung
  sMsgToSvr : String; // Nachricht für den Server
begin
  // als erstes die Usereingaben prüfen
  Timer2.Enabled := False;
  if OpenDialog1.Execute then
  begin
    FileSend := OpenDialog1.FileName;
    if not FileExists(FileSend) then
    begin
      Messagedlg('Die angegebene Datei existiert nicht, bitte wählen Sie eine Datei aus!',mtInformation,[mbok],0);
      exit;
    end;
    // als erstes versuchen die Datei zu öffnen, so das niemand mehr in diese Datei schreiben kann
    try
      fs := TFileStream.Create(FileSend,fmOpenRead or fmShareDenyWrite);
    except
      MessageDlg(FileSend+' kann nicht geöffnet werden ! '+#10#13
        +'Wahrscheinlich ist diese Datei von einer anderen Anwendung geöffnet !',
        mtError,[mbok],0);
      exit;
    end;
    if IdTcpClient1.Connected then
    begin
      // Übertragungskomponenten anzeigen
      TBXAlignmentPanel1.Visible := True;
      ProgressBar1.Visible := True;
      ProgressBar1.Position := 0;
      // jetzt muss der Server natürlich wissen wieviele Bytes vom Client kommen,
      // und wie die Datei heisst
      sMsgToSvr := ExtractFileName(FileSend);
      try
        try
          bError := false;
          SendSize := fs.Size;
          SendSize1 := SendSize;
          ProgressBar1.Min := 0;
          ProgressBar1.Max := iTmpSize;
          ProgressBar1.Position := 0;
          while iTmpSize > 0 do
          begin
            SendSize1 := iTmpSize;
            if SendSize1 > 1024 then SendSize1 := 1024;
            Dec(iTmpSize, SendSize1);
            ProgressBar1.Position := ProgressBar1.Position + SendSize1;
          end;
          IdTcpClient1.WriteInteger(4);
          IdTcpClient1.WriteLn(sMsgToSvr);
          IdTcpClient1.WriteInteger(SendSize);
          idTCPClient1.OpenWriteBuffer;
          idTcpClient1.WriteStream(fs, False, False, SendSize);
          idTCPClient1.CloseWriteBuffer;
        finally
          fs.Free;
          TBXAlignmentPanel1.Visible := False;
          ProgressBar1.Visible := False;
          ProgressBar1.Position := 0;
        end;
      except
        on E: Exception do
        begin
          ShowMessage(E.Message);
          bError := true;
          Log(101, E.Message);
        end;
      end;
      // War die Übertragung der DAtei erfolgreich ?
      if not bError then
      begin
        Log(100, 'File ' + sMsgToSvr + ' with ' + IntToStr(SendSize) + ' kbs has been sent!');
        PostMessage(avatar, 'File ' + sMsgToSvr + ' with ' + IntToStr(SendSize) + ' kbs has been sent!');
      end;
      if bError then
      begin
        Log(101, 'Failed to send the file!');
        PostMessage(avatar, 'Failed to send the file!');
      end;
    end;
  end;
end;
Der Server erhält den entsprechenden Befehl, die Größe der Datei sowie die Datei selber und schickt sie an alle angeschlossenen Clients:
(Achtung, hier ist die Lösung etwas anders als urprünglich gepostet, die Datei 'FileReceiver.pas' habe ich ganz weg gelassen)
Delphi-Quellcode:
procedure TfrmMain.tcpServerExecute(AThread: TIdPeerThread);
var
  Client : TSimpleClient;
  Com, // System command
  sMsgToClt, FileName, Msg: String;
  Count, FileSize, Cmd: Integer;
  ts : TMemoryStream;
  List : TList;
  CS : TCriticalSection;
begin
  { Get the clients package info }
  Client := Pointer(AThread.Data);
  { Check to see if the clients name has been assigned yet }
  if Client.Name = 'Logging Inthen
  begin
    { if not, assign the name and announce the client }
    Cmd := AThread.Connection.ReadInteger;
    if cmd = 2 then
    begin
      ... {Behandlung beim Einloggen eines Clients, tut hier nichts zur Sache, daher weggelassen}
    end;
  end
  else
  begin
    { If name is set, then send the message }
    Cmd := AThread.Connection.ReadInteger;
    if cmd = 4 then
    begin
      try
        try
          Msg := AThread.Connection.ReadLn;
          FileName := Msg;
          CS := TCriticalSection.Create;
          CS.Enter;
          sMsgToClt := '#' + FileName; //ExtractFileName(FileName);
          ts := TMemoryStream.Create; //(FileName, fmCreate or fmShareDenyNone);
          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;
      Exit;
    end;
    if cmd = 5 then
    begin
      ...
    end;
  end;
So, die Datei kommt bei den einzelnen Clients an, entweder in einer Timer-Routine oder einem Thread:
Delphi-Quellcode:
procedure TForm1.GetAct;
var
  Cmd, Com, Msg, Msg1, Msg2 : String;
  FileSize: integer;
  ftmpStream : TFileStream;
  ms : TMemoryStream;
begin
  if not IdTcpClient1.Connected then
    exit;
  try
    Msg := IdTCPClient1.ReadLn('', 5);
    if Msg <> 'then
    begin
      Msg1 := Copy(Msg, 3, Length(Msg) -1);
      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
            FileSize := IdTCPClient1.ReadInteger();
            IdTCPClient1.ReadStream(fTmpStream, FileSize, False);
            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);
          Timer2.Enabled := True;
        end;
      end;
      if Msg[1] = '°then
      begin
        ...
      end;
    end
    except
    ...
  end;
Ich habe versucht, das ganze recht einfach zu halten und daher lediglich beim Versand eine optische Anzeige eingefügt, ansonsten gibt es entsprechende Mitteilungen über Größe und Namen der gesendeten bzw, empfangenen Datei..
  Mit Zitat antworten Zitat