在Delphi中,FTP可以用于一般的文件传输吗?

在Delphi中,FTP可以用于一般的文件传输吗?,delphi,delphi-xe3,Delphi,Delphi Xe3,我正在使用TidTtilityFTP服务器n TidTtilityFTP进行p2p文件传输,它适用于文本文件传输,但当我尝试docx和pdf文件时,虽然文件已传输,但无法打开,或者pdf表示文件已损坏。如此链接所示 “FTP客户端基于普通文件传输协议。此客户端 可用于连接到TFTP服务器。TFTP不用于一般文件传输,因为它 是一种非常轻量级的文件传输协议。它通常仅限于局域网,用于 简单的任务,例如从路由器上传/下载路由表。由于 本协议的性质,在需要身份验证时不建议使用 或一般需要任何类型的担保”

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

“FTP客户端基于普通文件传输协议。此客户端 可用于连接到TFTP服务器。TFTP不用于一般文件传输,因为它 是一种非常轻量级的文件传输协议。它通常仅限于局域网,用于 简单的任务,例如从路由器上传/下载路由表。由于 本协议的性质,在需要身份验证时不建议使用 或一般需要任何类型的担保”

FTP和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;
普通FTP(TFTP)是一种基于UDP的轻量级文件传输协议。如描述所述,它通常仅用于简单传输,如与基于局域网的路由器交互。对于更健壮的传输,您应该使用基于TCP/IP的文件传输,例如使用
TIdFTP
TIdFTPServer
,甚至使用HTTP传输,例如使用
TIdHTTP
tidhtpserver

尽管如此,以下客户端线路是错误的:

stream.ReadBuffer(buffer, Length(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
)事件,因此直接访问
TSaveDialog
TMemo
组件是不安全的。您必须与主线程同步才能安全访问它们,例如:

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;

请出示你的密码。
TransferMode
属性可以设置为
tfNetAscii
,这对于ASCII文本文件很好,而
tfOctet
则用于二进制数据。提示:FTP具有类似的设置/模式。我需要一个通用的文件传输协议。代码添加在上面。@Marcus将其设置为tfoctet。@MarcusAdams:
TransferMode
实际上不是由
TidLittleFTP
TidLittleFTPServer
实现的。虽然
tidtilityftp
TransferMode
发送到TFTP服务器,并且
tidtilityftpserver
确实提取接收到的
TransferMode
,但两个组件实际上都没有使用指定的模式。它们都仅在
tfOctet
模式下执行传输。