2016-04-15 16 views
1

ウィザードを使用してスタンドアロンのDatasnap TCP/IPサーバーを作成しました。私はサンプルメソッドを選択しました(エコーストリングと逆ストリング)。私はサーバーを保存して実行しました。次に、クライアントアプリケーションを作成し、ファイルnew-otherを使用して、ClientClassesユニットとともにClientModuleをそのクライアントプロジェクトに追加しました。メインフォーム上。私はボタンを追加しました。ボタンのOnClickイベントハンドラでは、私は次のコードを追加:Delphi 10 Seattle Datasnapエラー:「操作が失敗しました。接続が閉じました。

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if ClientModule1.SQLConnection1.Connected then 
    begin 
    Button1.Text := 'Open'; 
    ClientModule1.SQLConnection1.Close; 
    end 
    else 
    begin 
    Button1.Text := 'Close'; 
    // ClientModule1.SQLConnection1.Open; 
    ClientModule1.ServerMethods1Client.ReverseString('myteststring'); 
    end; 
end; 

ここでの目的は、クライアントがサーバーにログインしてからログアウト定期的にではなく、接続を維持している状況をシミュレートすることです。これは、モバイルにデプロイされたアプリで特に重要です。

ServerMethods1クライアントへの最初の呼び出しで接続が開かれるため、Connection.Openをコメントアウトしたことが分かります。生成されたコードは次のとおりです。

function TClientModule1.GetServerMethods1Client: TServerMethods1Client; 
begin 
    if FServerMethods1Client = nil then 
    begin 
    SQLConnection1.Open; 
    FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, FInstanceOwner); 
    end; 
    Result := FServerMethods1Client; 
end; 

ここで問題が発生します。ボタンを最初にクリックすると、接続が開き、メソッドが呼び出されます。ボタンを2回クリックすると、接続が閉じられます。 3回目のクリックで、TDBXCommandコードで「操作が失敗しました。接続がクローズしました」という例外が発生します。回避策として

、私はこれを試してみました:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    if ClientModule1.SQLConnection1.Connected then 
    begin 
    Button1.Text := 'Open'; 
    ClientModule1.SQLConnection1.Close; 
    ClientModule1.ServerMethods1Client := nil; 
    end 
    else 
    begin 
    Button1.Text := 'Close'; 
    // ClientModule1.SQLConnection1.Open; 
    ClientModule1.ServerMethods1Client.ReverseString('myteststring'); 
    end; 
end; 

これはソートのClientModule1のFServerMethods1Clientインスタンスがリセットされているので、それは最初の実行でやったようなので、作成したコードを再度実行し、問題を解決しません。

他の唯一の問題は、(私はEurekalogを使用しています)メモリリークを作成することです。

私は間違っていますか?アプリを再起動せずにDatasnapサーバとの接続/切断を繰り返し行うには、どのような方法が適していますか?

答えて

-1

私のAndroid FMXの実装では、私は物事を完了するためにservermethodsを呼び出すだけです。 (つまり、私はDatasnapデータコンポーネントを使用しません)。モバイルデバイスで現実的に何かを考えようとすると、Datasnapアーキテクチャへの制御されないデータ転送オーバーヘッドがあまりにも多くあります。それを回避する(とメモリリークを持っていない)ために、私は今のようにTServermethods1Clientのローカルインスタンスを作成し、私はそれらを必要なときに、コンテキストでそれらを解放:

function TClientModule1.PostTheLog: Boolean; 
var 
    Server: TServerMethods1Client; 
begin 

    Server := TServerMethods1Client.Create(ClientModule1.SQLConnection1.DBXConnection); 
    try 
     UserID := Server.GetUserID; 
     ... 
    finally 
     Server.Free; 
    end; 
end; 

今ClientModule1.SQLConnection1を接続することができるとの切断します(好ましくはサーバメソッドへの呼び出しの直前に接続され、その後は切断されます)、それ以上の問題は発生しません。

これは、理想的な世界で、公開されているアクセス可能なServerMethods1Clientが実際に役立つだろうという疑問を引き起こします。

+0

これはうまくいきますが、毎回新しいインスタンスを作成して破棄するのではなく、接続が開いている間はクライアントプロキシインスタンスを割り当てたほうが効率的です。メモリ割り当て/管理は、特に代替案(繰り返し実行しない)と比較して高価です。 –

+0

あなたがあなた自身の質問に答えて、あなたが本当に提供した情報が元の質問に対する答えではないとき、答えとしてマークしたのは混乱しています。 –

+0

あなたは完全な答えを提供しても大丈夫です。それまでの間は、自分の答えで十分ですが、そうではありませんか? – nolaspeaker

2

最初のエラーの原因は、クライアント側のプロキシをバインドするコード(サーバーメソッドを呼び出すことができる)がローカルSQL接続に結びついているためです。

FServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection, ...) 

基になるDBExpress接続は参照渡しで、プロキシクラスはその接続を使用してサーバーを呼び出します。接続を閉じて再度開きましたが、ServerMethodsClient1が使用していた基礎となるDBExpress接続が破棄されました。したがって、 "Connection was closed"例外が表示されます。 ServerMethodsClient1が使用していた接続が閉じられました。 2番目の例のように、ServerMethodsClient1を再作成する必要があります。

私はそれがARC固有であると信じているので、私はあなたの2番目の質問に答えることができません。 VCL DataSnapアプリケーションでは、ServerMethodsClient1.Freeをnilに設定するのではなく、呼び出すことにしました。デルファイのARC実装(ニュースグループのすべて)の私の非常に限られた理解に基づいて、私はServerMethodsClient1.DisposeOfを呼び出す必要があると信じています。誰かがここに飛び込んで、ARCとメモリリークを起こすのではなくオブジェクトを破壊する適切な解決策を理解していると確信しています。

+0

ありがとうございました。あなたが言ったことは、一点まで意味があります。私は実際に毎日使用されている完全なVCLデータスナップアプリケーションを書いていますが、私はこの問題に遭遇したことはありません。何故なの?なぜなら、そのサーバーからデータを取得するために、設計時コンポーネント(TDSProviderConnectionとTSqlServerMethod)を使用していたからです。更新は対応するTClientDataset.Applyupdattesを介して行われます。私はどんなサーバーメソッドも呼び出さず、その実装とユーザーはアプリケーションを終了せずに終日接続したり切断したりする。詳細... – nolaspeaker

関連する問題