Can't retrieve TStreams bigger than around 260.000 bytes from a Datasnap Server

前端 未结 6 527
盖世英雄少女心
盖世英雄少女心 2020-12-11 06:05

I have a Delphi 10.1 Berlin Datasnap Server, that can\'t return Data packets (through a TStream) bigger than around 260.000 bytes.

I have programmed it following the

6条回答
  •  感动是毒
    2020-12-11 06:33

    I have coded a workaround. Seeing that I can't pass data bigger than 255Kb then I split it in different 255Kb packets and send them separately (I have also added compression to minimize the bandwidth and roundtrips).

    On the server I have changed StremGet to two different calls : StreamGet and StreamGetNextPacket.

    function TServerMethods.StreamGet(var Complete: boolean): TStream;
    var Data: TMemoryStream;
        Compression: TZCompressionStream;
    begin
      try
        // Opening Data
        qCustomers.Close;
        qCustomers.Open;
        qOrders.Close;
        qOrders.Open;
    
        // Compressing Data
        try
          if Assigned(CommStream) then FreeAndNil(CommStream);
          CommStream := TMemoryStream.Create;
          Data := TMemoryStream.Create;
          Compression := TZCompressionStream.Create(CommStream);
          FDSchemaAdapter.SaveToStream(Data, TFDStorageFormat.sfBinary);
          Data.Position := 0;
          Compression.CopyFrom(Data, Data.Size);
        finally
          Data.Free;
          Compression.Free;
        end;
    
        // Returning First 260000 bytes Packet
        CommStream.Position := 0;
        Result := TMemoryStream.Create;
        Result.CopyFrom(CommStream, Min(CommStream.Size, 260000));
        Result.Position := 0;
    
        // Freeing Memory if all sent
        Complete := (CommStream.Position = CommStream.Size);
        if Complete then FreeAndNil(CommStream);
      except
        raise;
      end;
    end;
    
    function TServerMethods.StreamGetNextPacket(var Complete: boolean): TStream;
    begin
      // Returning the rest of 260000 bytes Packets
      Result := TMemoryStream.Create;
      Result.CopyFrom(CommStream, Min(CommStream.Size - CommStream.Position, 260000));
      Result.Position := 0;
    
      // Freeing Memory if all sent
      Complete := (CommStream.Position = CommStream.Size);
      if Complete then FreeAndNil(CommStream);
    end;
    

    CommStream: TStream is declared as private on TServerMethods.

    And the Client retrieves it this way :

    procedure TClientForm.GetTables;
    var Complete: boolean;
        Input: TStringStream;
        Data: TMemoryStream;
        Decompression:  TZDecompressionStream;
    begin
      Input := nil;
      Data := nil;
      Decompression := nil;
    
      try
        // Get the First 260000 bytes Packet
        spStreamGet.ExecProc;
        Input := TStringStream.Create(spStreamGet.ParamByName('ReturnValue').AsBlob);
        Complete := spStreamGet.ParamByName('Complete').AsBoolean;
    
        // Get the rest of 260000 bytes Packets
        while not Complete do begin
          spStreamGetNextPacket.ExecProc;
          Input.Position := Input.Size;
          Input.WriteBuffer(TBytes(spStreamGetNextPacket.ParamByName('ReturnValue').AsBlob), Length(spStreamGetNextPacket.ParamByName('ReturnValue').AsBlob));
          Complete := spStreamGetNextPacket.ParamByName('Complete').AsBoolean;
        end;
    
        // Decompress Data
        Input.Position := 0;
        Data := TMemoryStream.Create;
        Decompression := TZDecompressionStream.Create(Input);
        Data.CopyFrom(Decompression, 0);
        Data.Position := 0;
    
        // Load Datasets
        DataModuleFDClient.FDSchemaAdapter.LoadFromStream(Data, TFDStorageFormat.sfBinary);
      finally
        if Assigned(Input) then FreeAndNil(Input);
        if Assigned(Data) then FreeAndNil(Data);
        if Assigned(Decompression) then FreeAndNil(Decompression);
      end;
    end;
    

    It works fine now.

提交回复
热议问题