как отправить файл с сервера на клиент, используя indy - PullRequest
0 голосов
/ 28 апреля 2018

Я ищу пример, как получить файл с сервера (я использую Indy) Я хочу отправить на сервер запрос

На клиенте:

MyIdTCPClient.IOHandler.WriteLn('SEND_FILE');
MyIdTCPClient.IOHandler.WriteLn('1.XLS');

На сервере

procedure TServerMainForm.IdTCPServerExecute(AContext: TIdContext); 
var AStream : TMemoryStream;
    filesize : Integer;
    line, filename: String;
begin

    line := AContext.Connection.IOHandler.ReadLn();
        if line = 'SEND_FILE' then
        begin
            filename := AContext.Connection.IOHandler.ReadLn();

            AStream := TIdFileStream.Create(filename, fmOpenRead + fmShareDenyNone);
           try
               AContext.Connection.IOHandler.Write('FILE_DOWNLOAD'); //send command "FILE"
               AContext.Connection.IOHandler.Write(ExtractFilename(filename)); // send file name
               AContext.Connection.IOHandler.Write(IntToStr(AStream.Size)); //send file size

               AContext.Connection.IOHandler.Write(AStream);
           finally
               FreeAndNil(AStream);

           end;

и затем на клиенте

if MyIdTCPClient.IOHandler.InputBufferIsEmpty then
  begin
    MyIdTCPClient.IOHandler.CheckForDataOnSource(10);
    if MyIdTCPClient.IOHandler.InputBufferIsEmpty then Exit;
  end;
  S := MyIdTCPClient.IOHandler.ReadLn();

  if S = 'FILE_DOWNLOAD' then
  begin
        MyIdTCPClient.IOHandler.LargeStream := True; 

        if MyIdTCPClient.IOHandler.InputBufferIsEmpty then
        begin
          MyIdTCPClient.IOHandler.CheckForDataOnSource(10);
          if MyIdTCPClient.IOHandler.InputBufferIsEmpty then Exit;
        end;

         Filename :=  MyIdTCPClient.IOHandler.ReadLn(); //filename
            S := MyIdTCPClient.IOHandler.ReadLn(); // filesize
            FileSize := StrToInt(S);
            AStream := TIDFileStream.Create(ExtractFilePath(Paramstr(0)) + '\XLS\' + Filename, fmCreate);
            try
                AContext.Connection.IOHandler.ReadStream(AStream, Filesize, False);
            finally
                FreeAndNil(AStream);
            end;

Но это не работает. Ни один файл не создается на клиенте; Вы можете мне помочь?

1 Ответ

0 голосов
/ 29 апреля 2018

При отправке ответа FILE_DOWNLOAD сервер вызывает IOHandler.Write(String) вместо IOHandler.WriteLn() для отправки строк FILE_DOWNLOAD и имени файла. Строки не заканчиваются на CRLF, но клиент использует ReadLn() для чтения этих строк. Таким образом, он никогда не достигает точки, где он пытается создать файл и прочитать его.

При этом я бы предложил несколько альтернативный дизайн для вашего протокола и кода.

Вам не нужно отправлять имена файлов в их собственных строках. Они должны быть в той же строке, что и команды, которым они принадлежат.

TIdIOHandler.Write(TStream) и TIdIOHandler.ReadString() могут обрабатывать отправку / чтение размера потока для вас. Вам не нужно отправлять / читать размер вручную, и, конечно, не в виде строки.

Попробуйте вместо этого:

Клиент

var
  XLSFolder: string;

...

MyIdTCPClient.IOHandler.WriteLn('SEND_FILE 1.XLS');

...

if MyIdTCPClient.IOHandler.InputBufferIsEmpty then
begin
  MyIdTCPClient.IOHandler.CheckForDataOnSource(10);
  if MyIdTCPClient.IOHandler.InputBufferIsEmpty then Exit;
end;
S := MyIdTCPClient.IOHandler.ReadLn();
Cmd := Fetch(S);
if Cmd = 'FILE_DOWNLOAD' then
begin
  AStream := TFileStream.Create(XLSFolder + S, fmCreate);
  try
    MyIdTCPClient.IOHandler.LargeStream := True;
    MyIdTCPClient.IOHandler.ReadStream(AStream, -1, False);
  finally
    AStream.Free;
  end;
end;

...

initialization
  XLSFolder := ExtractFilePath(Paramstr(0)) + 'XLS\';

Сервер

procedure TServerMainForm.IdTCPServerExecute(AContext: TIdContext);
var
  AStream : TFileStream;
  cmd, params, filename: String;
begin
  params := AContext.Connection.IOHandler.ReadLn();
  cmd := Fetch(params);
  if cmd = 'SEND_FILE' then
  begin
    filename := ExtractFilename(params);
    try
      AStream := TFileStream.Create('<some path>\' + filename, fmOpenRead or fmShareDenyWrite);
    except
      AContext.Connection.IOHandler.WriteLn('FILE_DOWNLOAD_ERR ' + filename);
      Exit;
    end;
    try
      AContext.Connection.IOHandler.WriteLn('FILE_DOWNLOAD ' + filename);
      AContext.Connection.IOHandler.LargeStream := True;
      AContext.Connection.IOHandler.Write(AStream, 0, True);
    finally
      AStream.Free;
    end;
  end;
end;
...