2011-08-15 16 views
7

短い紹介:傍受し、サーバーとユーザーの入力を承認する方法

私はシングルユーザーデスクトップバージョンにするために使用[物理学]シミュレーションフレームワークを持っています。このフレームワークは、例えば、教師はJavaプログラミングや特定の数学の詳細な知識なしにさまざまな種類のシミュレーション設定を構築できます。結局のところ、このアイデアは、クライアント/サーバのパラダイムをフレームワークに適用し、複数のクライアントが同じシミュレーションを使用して共同作業を行うことを可能にしました(すべてのクライアントでシミュレーションを同期させる)。

いくつかの追加の技術的な事実:

は、フレームワーク/シミュレーションは、MVCパターンに基づいて設計されています。

クライアントがシミュレーションへの変更を実行する場合(たとえば、スライダを動かしたりシミュレーション要素をマウスでドラッグしてSwing GUIを介して)、これらの変更はシミュレーションに適用される前にサーバによって承認されなければなりませんサーバーは他のすべてのクライアントに変更を配布するために注意を払わなければなりません。

承認自体は非常に簡単で、基本的には変更を受け入れる必要があるかどうかをタイムスタンプで決定するだけです(異なる遅延を持つクライアントによって引き起こされる問題を避けるために同じ時間に同じものが変更されます)。

問題、それぞれの質問:

私は今、ユーザー入力が(クライアント - を担当する基礎となるメッセージングシステムにそれらを渡すために検出(およびインターセプト)するための最もエレガントな方法は何思ったんだけどサーバー通信)?記載されたシナリオで一般的に使用されるパターンやベストプラクティスがありますか?

主な懸念事項の1つは、新しいコンテンツ(=シミュレーション)を構築するためにフレームワークを使用する人が考慮する必要がある新しい制約を導入することを避けることです。この意味では、既存のシミュレーションをできるだけ変更する必要はほとんどありません。

私はのような新しいインターフェイスを導入することについて考え:この場合の制約は、あらゆるタイプの変更リスナーが持っているということだろう

public interface Synchronizable { 
    public boolean appliesChanges(); 
} 

私は仕事ができると思った

一つの解決策リスニングしている変更イベントを同期させたい場合は、このインタフェースを追加実装する必要があります。そうすることで、基盤となるフレームワークは、Synchronizableを実装するすべてのオブジェクトを、変更(イベント)をサーバーと(そして実際の変更リスナーにイベントを成功裏に転送して)検証する役割を担うプロキシオブジェクトと置き換えることができます。

「applyChanges」メソッドの背後にあるアイデアは、変更リスナーへのすべての呼び出しが実際に同期を必要とする変更をもたらすわけではないということです。たとえば、スウィングJSliderは、ノブが動かされるたびにイベントを生成するかもしれませんが、変更リスナーの具体的な実装は、ノブが解放された後でのみ(実際には値は調整されません)途中で発生する変更イベントは、いずれにしても効果がないため、サーバーに送信する必要はありません。このアプローチは便利ではなく、特にきれいではありませんでしたが、別の方法で問題を解決する他の可能性は考えられませんでしたか?

エンドユーザーは、どのイベントを同期させたいのかを明示的に考える必要があるという問題のほかに、特定のリスナーすべてに対して前述のインターフェイスを宣言し実装するという問題のほかに、すべての可能な変更リスナーに対して具体的なプロキシを実装しなくてもよいように、任意のタイプのイベントを処理する特定のメソッドを特定します。この問題を概説

例:

public interface SynchronizedChangeListener extends ChangeListener, Synchronizable {} 
public interface SynchronizedPropertyChangeListener extends PropertyChangeListener, Synchronizable {} 

public static void main(String[] args) { 

    SynchronizedChangeListener scl = new SynchronizedChangeListener() { 
    public void stateChanged(ChangeEvent e) { 
     System.out.println("Hello world - SynchronizedChangeListener"); 
    } 
    public boolean appliesChanges() { 
     return true; 
    } 
    }; 
    SynchronizedPropertyChangeListener spcl = new SynchronizedPropertyChangeListener() { 
    public void propertyChange(PropertyChangeEvent evt) { 
     System.out.println("Hello world - SynchronizedPropertyChangeListener"); 
    } 
    public boolean appliesChanges() { 
     return true; 
    } 
    }; 
} 

どのようにプロキシリスナーがのPropertyChangeEventsのために、それはそれはのstateChanged 'メソッドを呼び出す必要がありでChangeEventのためのに対し、「のpropertyChange」メソッドを呼び出す必要があることを知っているだろうか?反射はこの問題を解決することができますか?

あなたのご意見をお待ちしております - このトピックを扱っている文献や今後の方向性についてお礼を申し上げます。

+0

+1私は間違っていると誰かが答えを与えることができます、私はHigherLevelMessagingについてお勧めしますが、問題の良い説明のために+1が、おそらくより良いフォーラム '学術的なdiscusions'ですhttp://programmers.stackexchange.com/です。 RMI、CobraまたはLowLevel ServersSocket – mKorbel

答えて

0

私はあなたにユーザーの入力を提供できるユーザーUIを持っています。物理シミュレーションを実行している別のシミュレーションUIがあります。ユーザーのUIからの入力は、サーバーがそれを承認した後にのみ、他のユーザーに入力する必要があります。

これまでのところとても良いですか?

これで、Simulation UIはサーバーからのイベントを最終的に待つ必要があります。私は次のようなことを考えていました:

  1. ユーザが望む変更を含むXMLをユーザuiから準備します。
  2. Tomcatサーバー上に単純なサーブレット(またはストラット)を実装して、このXMLを解析し、許可を求めてユーザーに応答します。応答はXMLでも可能です。
  3. キューを介してシミュレーションUIにこの権限を戻します。シミュレーションUIは、このキューに置かれたすべてのイベントをリスンする必要があります。
  4. これは、単一のユーザーシナリオを処理します。複数のユーザーがサーバーからイベントを受信する場合、これを行う最も簡単な方法はポーリングです。サーバーをポーリングするシミュレーションUIの前のレベルにタイマーを実装します。サーバーは最新の変更を返すことができます。これをシミュレーションUIのキューに入れます。
0

私はあなたの質問を理解していませんが、その根底には複数のクライアントが同時に潜在的に同時にサービスの状態を変更できるようにするという同時性の問題があるようです。

私が理解しているように、ユーザはシステムの状態(あなたのシミュレーション)を見て変更することができるクライアントを持っています。クライアント側では、リスナーがUIからの変更を待っているイベントベースのMVCがあり、その変更をサーバーに通知するクライアントに渡します。非常に初歩的な意味では、このように:私が正しくあなたの提案されたソリューションを理解していれば

Today: 
--------     ------------------    ---------- 
| UI | - change event -> | Event Listener | - set value -> | Server | 
--------     ------------------    ---------- 

、あなたはこれらのイベントをインターセプトし、最初の変更を行おうとする前に、誰もが、最近の状態を変更した場合、サーバーをお願いしたいと思います。

Proposed: 
--------     ------------------   ------------------    ---------- 
| UI | - change event -> | Proxy Listener | - event -> | Event Listener | - set value -> | Server | 
--------     ------------------   ------------------    ---------- 
            | 
           timestamp 
            | 
            v 
           ---------- 
           | Server | 
           ---------- 

私の意見では、これはさまざまな理由で理想的な解決策ではありません。まず、サーバーと2度話しています。次に、存在するさまざまなタイプのイベントハンドラのプロキシを作成する方法を理解する必要があります。「どのメソッドを呼び出すかを知るにはどうすればよいか」で説明したとおりです。これには、複数の異なるプロキシリスナ実装、または非常に乱雑な反射ロジックが必要です。最後に、毎回追加されるプロキシ・リスナーに依存する必要があるため、並行安全性はデフォルトではありません。

現在のユースケースや将来の拡張に適用できるより一般的な解決策は、サーバーへの設定値呼び出しを安全にすることです。つまり、イベントリスナーが最新の値(「値が失効しました」)に変更を加えようとすると、サーバーはそれを検出し、その場合はその変更を拒否します。この場合、解決すべき2つの小さな問題があります。古い状態での変更を検出する方法と、その変更が実行されなかったことをクライアントに伝える方法です。

最初の問題は、オプティミスティック・ロックのいくつかの形式を実装したい場合があります。提案されたソリューションと同様に、タイムスタンプを使用することができます。たとえば、UIがレンダリングされると、サーバーから値が取得されます。サーバーは、値と、その値が最後に変更されたときのタイムスタンプを戻すことができます。ユーザーが変更を行うと、クライアントは新しい値をサーバーに戻し、元の最後に変更されたタイムスタンプを戻します。 (つまり、「サーバ、fooを10に設定し、最後に誰かがfooを変更したのは昨日でした」)。サーバは、あなたの変更が最新の値であるかどうかを知り、そうでなければ変更を拒否することができます。

最後に変更されたタイムスタンプを変更する可能性のあるすべての値とともに保存する機能がない場合は、同じことをハッシュで実行できます。サーバーが値をクライアントに返すと、その値でハッシュを計算して返します。サーバーが更新要求を受け取ると、クライアントはハッシュを戻し、サーバーはその値からハッシュを再計算することができます。一致した場合、クライアントの変更は最新の値になります。

(用語の警告:あなたはタイムスタンプまたはハッシュを使用するかどうか、この値はとして役立つ「ミューテックス。」)

あなたはそう、どのようにクライアントとサーバーの相互作用についての詳細の全体の多くを提供していません。私はそこでのインターフェイスについてのみ推測することができますが、サーバー側でサーバー側のセッションでクライアントを追跡する機能がある場合は、適切なミューテックス値をサーバー側に格納して提供する作業を行うことができます。この場合、サーバは、特定のセッションに対して特定のクライアントに提供された値と、ミューテックス値は何かを追跡します。クライアントが同じセッションで更新要求を返すと、サーバーはその値のミューテックスをルックアップし、サーバーがそうしていることをクライアントが知らずにも適切なアクションを実行できます。この場合、現在の外観からクライアントをまったく変更することなく、並行安全なコードを適用することができます。

第2の問題点として、変更が却下されたために拒否されたことをクライアントに通知する方法については、クライアントとサーバーのやり取りの仕方によっては比較的簡単です。リモートの例外を許可するSOAPまたはRPCを使用している場合は、JavaのConcurrentModificationExceptionに似た何かをスローすることをお勧めします。その場合は、ビュー内に例外をキャッチし、それを適切に処理するだけです。つまり、サーバーを再度呼び出して最新の値を取得し、シミュレーションの状態がその下から変更されたため、要求された更新が受け入れられなかったことをユーザーに通知する可能性があります。

0

同期にはコンセンサスが必要です。シミュレーションで偏差(読み込みの不連続性)を許容できる場合は、更新が伝播されたときに別のステーションで設定された値をクライアントが強制的に受け入れるようにすることができます。シミュレーションローカルクロックがある場合は、この値を使用してアップデートを出荷することができます。これにより、変更によって結果が異なる可能性があります。

他の回答は、複数の通信の問題と、mutexを使った同期の可能性について考えます。

1つの方法は、リソースがタッチされたときにリソースをロックすることです(インストラクターの設定や上書きを使用するなど)。ロックをパブリッシュしてローカル変更を防ぎ、ロックが解放されるまで更新を配布します。

指定されたユーザーだけがロックを暗黙的に変更する変数を制御できる非対称クライアントがある場合は、ロックを回避できます。

すべてのクライアント変数のマルチキャスト(実際のまたはpub-subのいずれかの配布)を使用する場合、これは特定のサポートを必要としないスケジュールされた状態更新の一部を形成できます調整最適化)。

実際に決定するのは、マルチマスターの更新を許可するのか、または単一のソースからの変更を制限するのかです。これにより、アルゴリズム、プロトコル、および実装が根本的に決定されます。

関連する問題