Search code examples
delphidelphi-7indy-9

Need help sending file with Indy


  1. I use TIdTCPServer and TIdTCPClient, both client and server are on the same local network with 100 mbps
  2. Need to send files upto 2 MB each
  3. I have no experiences with Indy and Socket programming

*After the client send request to the server, it then looping until disconnect from the server, the file is created with the client itself but has 0 byte in size

IdTCPServer.OnExecute ...

begin
  CS.Enter;

  try
    InputString := AThread.Connection.ReadLn;

    if InputString = 'PIC' then begin
      AFullFileName := FFilePath + 'PIC01.jpg';
      if FileExists(AFullFileName) then begin
        AFileStream := TFileStream.Create(AFullFileName, fmOpenRead + fmShareDenyNone);

        AThread.Connection.OpenWriteBuffer;
        AThread.Connection.WriteStream(AFileStream);
        AThread.Connection.CloseWriteBuffer;

        FreeAndNil(AFileStream);
      end;

      AThread.Connection.Disconnect;
    end;
  except
    on E : Exception do
      ShowMessage(E.Message);
  end;

  CS.Leave;
end;

Client.OnButtonClick ...

begin
  with IdTCPClient do begin
    if Connected then Disconnect;
    Host := '127.0.0.1';
    Port := 2018;
    Connect;
    WriteLn('PIC');
    //different folder with server's folder
    if FileExists(FFilePath + 'PIC01.jpg') then
      DeleteFile(FFilePath + 'PIC01.jpg');
    AFileStream := TFileStream.Create(FFilePath + 'PIC01.jpg', fmCreate);
    while Connected do
      ReadStream(AFileStream, -1, true);
    FreeAndNil(AFileStream);
    Disconnect;
  end;
end;

Thanks all.


Solution

  • You are making a classic newbie mistake of mismatching the WriteStream() and ReadStream() calls. By default, WriteStream() DOES NOT send the stream size, but the parameter values you are passing to ReadStream() tell it to expect the stream size.

    Other mistakes you are making:

    1. You are calling ReadStream() in a loop, but not calling WriteStream() in a loop.

    2. Wrapping your entire OnExecute code in a critical section. Don't do that.

    3. Wrapping your entire OnExecute code in a try/except that swallows all exceptions. DO NOT swallow EIdException-derived exceptions. TIdTCPServer needs to handle them.

    4. Calling ShowMessage(). It is not thread-safe. Use Windows.MessageBox() instead.

    5. Using write buffering with WriteStream(). That is a huge waste of memory for large files. Get rid of that.

    Update: try this:

    Server:

    begin
      InputString := AThread.Connection.ReadLn;
      if InputString = 'PIC' then begin
        AFullFileName := FFilePath + 'PIC01.jpg';
        AFileStream := TFileStream.Create(AFullFileName, fmOpenRead or fmShareDenyNone);
        try
          AThread.Connection.WriteStream(AFileStream, True, True);
        finally
          AFileStream.Free;
        end;
      end;
      AThread.Connection.Disconnect;
    end;
    

    Client:

    begin
      if IdTCPClient.Connected then IdTCPClient.Disconnect;
      IdTCPClient.Host := '127.0.0.1';
      IdTCPClient.Port := 2018;
      if FileExists(FFilePath + 'PIC01.jpg') then
        DeleteFile(FFilePath + 'PIC01.jpg');
      AFileStream := TFileStream.Create(FFilePath + 'PIC01.jpg', fmCreate);
      try
        try
          IdTCPClient.Connect;
          try
            IdTCPClient.WriteLn('PIC');
            IdTCPClient.ReadStream(AFileStream, -1, False);
          finally
            IdTCPClient.Disconnect;
          end;
        finally
          AFileStream.Free;
        end;
      except
        DeleteFile(FFilePath + 'PIC01.jpg');
      end;
    end;