how to send file from server to client using indy

这一生的挚爱 提交于 2021-02-07 09:43:32

问题


I look for an example, how to receive a file from server (I use Indy) I want to send to server some demand

On client:

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

On Server

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;

and then on Client

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;

But it doesn't works. Any file is not created on client; Can you help me?


回答1:


When sending the FILE_DOWNLOAD reply, the server is calling IOHandler.Write(String) instead of IOHandler.WriteLn() to send the FILE_DOWNLOAD and filename strings. The strings are not being terminated with CRLF, but the client is using ReadLn() to read those strings. So it never reaches the point where it tries to create the file and read into it.

That being said, I would suggest a slightly alternative design for your protocol and code.

You don't need to send filenames on their own lines. They should be on the same lines as the commands that they belong to.

TIdIOHandler.Write(TStream) and TIdIOHandler.ReadString() can handle sending/reading the stream size for you. You don't need to send/read the size manually, and certainly not as a string.

Try this instead:

Client

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\';

Server

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;


来源:https://stackoverflow.com/questions/50079812/how-to-send-file-from-server-to-client-using-indy

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!