4

这是我在这里的第一篇文章-所以要温柔:-)

我想构建一个使用 datasnap 进行数据传输的客户端/服务器应用程序。这是一个相当简单的任务——有很多例子可以学习。但是 - 拥有一个 Datasnap 服务器(从 Delphi XE 向导构建)我发现自己遇到了一个问题,我希望有人能引导我走向正确的方向。

服务器和客户端在同一台 PC 上运行(这是目前的设计)。服务器正在运行会话生命周期。服务器和客户端共享一个类(发布在下面)..

服务器提供了一个简单的方法——GetServerObject,它使用GetNewObject 方法。服务器本身是一个 VCL 应用程序 - 主要形式是 fmServer。OnCreate 实例化 Servers FormObject 属性 (FormObject := TMyDataObject.Create);

function TServerMethods2.GetNewObject: TMyDataObject;
begin
  Result := TMyDataObject.Create;
end;

function TServerMethods2.GetServerObject: TMyDataObject;
begin
  Result := GetNewObject;
  if not Result.Assign(fmServer.FormObject) then
    raise Exception.Create('Server error : Assign failed!');
end;

所有这一切都是微不足道的 - 只有当我将我的客户端应用程序扭曲成一个多线程怪物时才会出现我的问题:-)(阅读 - 超过 1 个线程)。

所以这里是客户端的线程代码。

  TDataThread = class(TThread)
  private
    DSConn: TSQLConnection;
  protected
    procedure Execute; override;
  public
    constructor Create(aConn: TSQLConnection); overload;
  end;

constructor TDataThread.Create(aConn: TSQLConnection);
begin
  inherited Create(False);
  DSConn := aConn.CloneConnection;
  FreeOnTerminate := true;
end;

procedure TDataThread.Execute;
var
  DSMethod: TServerMethods2Client;
  aDataObject : TMyDataObject;
begin
  NameThreadForDebugging('Data');
  { Place thread code here }
  DSMethod := nil;
  try
    while not terminated do
    begin
      sleep(10);
      if DSConn.Connected then
      begin
        try
          if DSMethod = nil then
            DSMethod := TServerMethods2Client.Create(DSConn.DBXConnection,false);
          if DSMethod <> nil then
            try
              aDataObject := DSMethod.GetserverObject;
            finally
              freeandnil(aDataObject);
            end;
        except
          freeandnil(DSMethod);
          DSConn.Connected := False;
        end
      end
      else
      begin
        // connect
        try
          sleep(100);
          DSConn.Open;
        except
          ;
        end;
      end;
    end;
  finally
    freeandnil(DSMethod);
    DSConn.Close;
    freeandnil(DSConn);
  end;

当我创建超过 1 个这些线程时 - 最终我会收到一个错误(“无法实例化......”或一些“远程 dbx 错误......”......等等。

我根本无法让它工作——这样我就可以产生数百个线程/连接到数据快照服务器。

我知道这个问题很棘手——但我希望有人比我聪明:-)

如果我尝试相同的客户端线程代码 - 但访问更简单的服务器方法(让我们说来自示例的 echostring),那么我可以使用数百个线程运行它。也许我在这里回答自己 - 但我太盲目了,无法意识到它:-)

unit uDataObject;

interface

uses
  SysUtils;

Type
  TMyDataObject = class(TObject)
  private
    fString: String;
    fInteger: Integer;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    function Assign(aSource: TMyDataObject): boolean;
    property aString: String read fString write fString;
    property aInteger: Integer read fInteger write fInteger;
  end;

implementation

{ TMyDataObject }

function TMyDataObject.Assign(aSource: TMyDataObject): boolean;
begin
  if aSource <> nil then
  begin
    try
      fString := aSource.aString;
      fInteger := aSource.aInteger;
      Result := True;
    except
      Result := false;
    end;
  end
  else
    Result := false;
end;

constructor TMyDataObject.Create;
begin
  inherited;
  Randomize;
  fString := 'The time of creation is : ' + FormatDateTime('ddmmyyyy hh:nn:ss:zzz', Now);
  fInteger := Random(100);
end;

destructor TMyDataObject.Destroy;
begin
  inherited;
end;
end.

感谢所有帮助

4

2 回答 2

0

When the simple server method is working, i think your problem has to be found i somethin the "real" code is doing or using.

It could be in the connection (try changing your simpler code to use the connection) Your problem can also be then CloneConnection. The Cloned connection is freed, when the connection it is cloned from is freed. See http://docwiki.embarcadero.com/VCL/en/SqlExpr.TSQLConnection.CloneConnection

于 2011-04-08T07:56:05.563 回答
0

This has mostly been answered in the comments and the bug report, but... The problem you are seeing is caused by a multithreading issue in XE's marshaller code. If two threads (or two clients) call a server server method which takes in or return user defined types (any type which will use the marshaller/unmarshaller) at the same time, then an exception could happen.

I am unaware of a perfect workaround for XE, but if it is possible to not use user-defined types, then you shouldn't see multithreading issues.

Mat

于 2011-05-03T14:46:10.903 回答