0

私は現在、主にサーバーへのプロシージャ呼び出しを行い、パケット応答を待機するように構築されたクライアントサーバーアプリケーションを作成しています。

ただし、サーバーにニュースをクライアントに「プッシュ」させたいのですが(自発的に)、クライアントが別のパケット応答をリッスンするときにメッセージが到着した場合、それは問題のようです。

同じソケットインスタンスを介して、ソケットを2つの一意のチャネルストリームに分割する方法はありますか?または、着信接続のみをリッスンしてキューにディスパッチするクライアントスレッドを作成する方がよいでしょうか。

双方向のクライアントサーバー接続を使用する場合の一般的なパターンとプラクティスは何ですか?(ストリームが自発的に発生する場所)

リマインダーとして、Java Socket、ObjectInputStream、ObjectOutputstreamを使用しています。JavaRMIを使用していません。

4

2 に答える 2

2

したがって、ネットワーキングについて学ぶときに直面することの1つは、同期の喪失です。これは、たとえば、特定のクライアント/サーバー相互作用のセットを「ハードコーディング」した場合に発生します。

server sends 2 byte status code
client receives 2 byte status code
client responds with 4 byte operation code

何らかの理由で、この相互作用の一部が必要に応じて正確に発生しないバグがある場合、すべてのネットワーク相互作用が同期していないため、プログラムの残りの部分は失敗します。クライアントは、実際にサーバーがintを送信しているときなど、文字列を表すと信じるバイトのセットを読み取る可能性があります。最悪の場合、クライアントとサーバーの両方が同時に入力を待機しているため、メインネットワークスレッドがデッドロックしていることに気付くかもしれません。

確かにバグがある大規模なプロジェクトでは、このスタイルでコーディングすると、これは非常に多く発生します。このため、ミドルウェアと呼ばれるものがあります。

非常に一般的で柔軟なミドルウェアパラダイムは、TLVメッセージプロトコルです。いくつかの単純なクラスを(semi-java-pseudocodeで)実装します。

TLVMessage
    int type;
    byte[] value;

TLVPusher implements Runnable
    OutputStream out;
    Queue<TLVMessage> messages;
    run() {
        while(true) {
            //poll and write front of queue to out (INCLUDING value.length!)
        }
    }

TLVReader implements Runnable
    InputStream in;
    Queue<TLVMessage> messages;
    run() {
        while(true) {
            //read message from in and add to queue
        }
    }

これで、クライアントで2つのスレッドが実行され、サーバーで2つのスレッドが実行されます。それぞれの端には独自のPusherとがありReaderます。注意すべき重要な点は、長さフィールドを出力ストリームに書き込むため、リーダーは常に読み取る必要のあるバイト数を知っているということです。したがって、1つのメッセージが誤ってシリアル化された場合でも、その長さは正しく、次のメッセージは常に最初のバイトから最後のバイトまで正しく読み取られます。このようにして、プログラムが同期しなくなることはありません。

TLVMessageにオブジェクトを追加するだけで、ソケットのもう一方の端にオブジェクトpusher.queueが到着します。reader.queue次に、メッセージをフィールドごとに処理できます(別の3番目のスレッドで監視reader.messages.size()します)type

物事がどのような順序で発生するかを心配する必要はありません。クライアントとサーバーの間で2つの方向にメッセージを渡すための堅牢なメカニズムがあります。あなたは厄介なネットワークのものを抽象化し、コーディングに取り掛かることができます。

もちろん、これをすべて行うライブラリはありますが、私の意見では、その方法理由を理解することは常に価値があります。

于 2012-11-07T09:00:15.937 に答える
0

ソケットに直接コーディングする必要がありますか?OSIスタックの上位に移動して、たとえばを使用するのは良い候補のように思えます。目標を達成するためのJMS 。

お役に立てば幸いです。

乾杯、

于 2012-11-07T08:56:10.797 に答える