【问题标题】:Can Tidtrivialftp be used for general file transfer in Delphi?Tidtrivialftp 可以用于 Delphi 中的一般文件传输吗?
【发布时间】:2013-12-16 15:24:39
【问题描述】:

我正在使用 tidtrivialftp 服务器 n tidtrivialftp 进行 p2p 文件传输,它适用于文本文件传输,但是当我尝试 docx 和 pdf 文件时,虽然文件已传输但无法打开或 PDF 说它已损坏。正如此链接所说@ 987654321@

"TIdTrivialFTP 客户端基于普通文件传输协议。此客户端 可用于连接到 TFTP 服务器。 TFTP 不适用于一般文件传输,因为它 是一个非常轻量级的文件传输协议。它通常仅限于 LAN 并用于 简单的任务,例如从路由器上传/下载路由表。因为 本协议性质,需要认证时不推荐使用 或一般需要任何类型的安全性”。

TIdTrivialFTP 和 TFTP 是不是不同,或者上面的文本是否相同?

这里是代码

客户:

procedure TForm2.LoadClick(Sender: TObject);
begin
  OpenDialog1.InitialDir := GetCurrentDir;

  if OpenDialog1.Execute then
  begin
    Edit1.Text := OpenDialog1.FileName;
    path := Edit1.Text;                      // save path for sending
  end;
end;

procedure TForm2.sendClick(Sender: TObject);
var
  size: Word;
  index: Word;
  buffer: TIdBytes;
begin
  stream := TFileStream.Create(path,fmOpenRead or fmShareDenyWrite);
  try
    setlength(buffer, stream.Size);
    stream.ReadBuffer(buffer, Length(buffer));
    stream.Position := 0;

    Client1.Put(stream, ExtractFileName(path));
  finally
    stream.Free;
  end;
end;

procedure TForm2.client1Work(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
begin
  Memo1.Lines.Add(IntToStr(AWorkCount));
end;

procedure TForm2.client1WorkBegin(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCountMax: Int64);
begin
  Memo1.Lines.Add('Transmitting data...');
end;

procedure TForm2.client1WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
  Memo1.Lines.Add('Transfer complete...');
end;

procedure TForm2.FormCreate(Sender: TObject);
begin    
  server.Create;
  server.ThreadedEvent := True;
  server.Active := True;
  server.Bindings.Add.Port := 69;

  Client1.Host := '';
  Client1.Port := 69;
end;

服务器:

procedure TForm2.serverWriteFile(Sender: TObject; var FileName: string;
  const PeerInfo: TPeerInfo; var GrantAccess: Boolean; var AStream: TStream;
  var FreeStreamOnComplete: Boolean);
var
  FS: TFileStream;
begin
  SaveDialog1.FileName := ExtractFileName(FileName);
  if SaveDialog1.Execute then   
  begin
    // let TIdTrivialFTPServer create the TFileStream internally...
    FileName := SaveDialog1.FileName;
    Memo1.Lines.Add('started writing files...');
    // file1 := ExtractFileName(Filename);
    { Open file in WRITE ONLY mode }
    FS := TFileStream.Create(TFTPPath + Filename,fmCreate or fmShareExclusive);
    { Copy all the data }
    AStream := FS;
    { Set parameters }
    FreeStreamOnComplete := True;
  end
  else
    GrantAccess := False;
end;

【问题讨论】:

  • 请出示您的代码。 TransferMode 属性可以设置为tfNetAscii,它适用于 ASCII 文本文件,tfOctet,它适用于二进制数据。提示:FTP 有类似的设置/模式。
  • 我需要一个通用的文件传输协议。代码在上面添加。
  • @Marcus 它设置为 tfoctet。
  • @MarcusAdams: TransferMode 实际上不是由TIdTrivialFTPTIdTrivialFTPServer 实现的。尽管TIdTrivialFTPTransferMode 发送到TFTP 服务器,并且TIdTrivialFTPServer 确实提取了接收到的TransferMode,但这两个组件实际上都没有使用指定的模式。他们都只在tfOctet模式下进行传输。

标签: delphi delphi-xe3


【解决方案1】:

Trivial FTP (TFTP) 是一种基于 UDP 的轻量级文件传输协议。正如描述所说,它通常仅用于简单的传输,例如与基于 LAN 的路由器交互。对于更可靠的传输,您应该改用基于 TCP/IP 的文件传输,例如使用 TIdFTPTIdFTPServer,甚至使用 HTTP 传输,例如使用 TIdHTTPTIdHTTPServer

话虽如此,以下客户端行是错误的:

stream.ReadBuffer(buffer, Length(buffer));

您没有正确地将stream 内容读入buffer,因此您正在破坏堆栈上的内存。您使用的是动态数组,因此您必须对数组进行索引,以便将数组分配的内存地址传递给ReadBuffer(),例如:

stream.ReadBuffer(buffer[0], Length(buffer));

或者:

stream.ReadBuffer(Pointer(buffer)^, Length(buffer));

你为什么要将文件数据读入本地TIdBytes?除了浪费内存之外,您不会将其用于任何其他用途,因此请摆脱它:

procedure TForm2.sendClick(Sender: TObject);
var
  stream: TFileStream;
begin
  stream := TFileStream.Create(path, fmOpenRead or fmShareDenyWrite);
  try
    Client1.Put(stream, ExtractFileName(path));
  finally
    stream.Free;
  end;
end;

在服务器端,OnWriteFile(和OnReadFile)事件在工作线程中触发,因此直接访问您的TSaveDialogTMemo 组件是不安全的。您必须与主线程同步才能安全访问它们,例如:

procedure TForm2.serverWriteFile(Sender: TObject; var FileName: string;
  const PeerInfo: TPeerInfo; var GrantAccess: Boolean; var AStream: TStream;
  var FreeStreamOnComplete: Boolean);
begin
  GrantAccess := False;
  TThread.Synchronize(nil,
    procedure
    begin
      SaveDialog1.FileName := ExtractFileName(FileName);
      GrantAccess := SaveDialog1.Execute;
      if GrantAccess then FileName := SaveDialog1.FileName;
   end
  );
  if GrantAccess then
  begin
    { Open file in WRITE ONLY mode }
    AStream := TFileStream.Create(Filename, fmCreate or fmShareExclusive);
    FreeStreamOnComplete := True;
    TThread.Synchronize(nil,
      procedure
      begin
        Memo1.Lines.Add('started writing a file...');
      end
    end;
  end;
end;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多