DELPHI:多线程客户端/服务器datasnap错误

时间:2011-04-07 11:23:05

标签: multithreading delphi datasnap

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

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

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

Server提供了一个简单的方法 - 使用GetNewObject方法的GetServerObject。 服务器本身是一个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;

当我创建多个这些线程时 - 最终我会收到错误(“无法实现...”或某些“远程dbx错误......”等等。

我根本无法让它工作 - 所以我可以产生数百个线程/连接到datasnap服务器。

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

如果我尝试相同的客户端线程代码 - 但访问一个更简单的服务器方法(比如说样本中的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.

感谢所有帮助

2 个答案:

答案 0 :(得分:0)

当简单的服务器方法工作时,我认为你的问题必须在“真正的”代码正在做或正在使用。

它可能在连接中(尝试更改更简单的代码以使用连接) 您的问题也可以是CloneConnection。克隆的连接在释放克隆的连接时被释放。看到 http://docwiki.embarcadero.com/VCL/en/SqlExpr.TSQLConnection.CloneConnection

答案 1 :(得分:0)

这在评论和错误报告中已经得到了回答,但是......您看到的问题是由XE的编组器代码中的多线程问题引起的。如果两个线程(或两个客户端)调用服务器服务器方法,该方法同时接收或返回用户定义的类型(将使用marshaller / unmarshaller的任何类型),则可能发生异常。

我不知道XE的完美解决方法,但是如果可以不使用用户定义的类型,那么你不应该看到多线程问题。