2010-11-18 7 views
4

2つのプロセスがTCPソケット経由で通信している別のマシンで動作しています。
両方のプロセスには、サーバーとしてもクライアントとしても機能するコードがあります。
I. ProcessAがportXでバインドするサーバーソケットを開き、ProcessBがportYでサーバーソケットバインドを開いています。
ProcessAはProcessBに接続してクライアントとしてメッセージを送信するためにクライアントソケットを開きます と応答を受信します(もちろん同じtcp接続を介して)。
ProcessBメッセージを受信して​​処理すると、応答を送信しますが、2番目のTCP接続、つまりProcessBがProcessAのportXへのクライアントソケットを開いたところでメッセージを送信することもできます。
したがって、メッセージの流れは、2つの異なるtcp接続で行われます。
私の問題は、次のとおりです。は、この「アーキテクチャ」を変更することはできませんし、そのまま滞在しなければならないことを許可されたとして取る:
を私は断続的に、メッセージがProcessBが持っているTCP接続でProcessAにProcessBから送信する問題を抱えていますProcessAがクライアントソケットとして接続したtcp接続を介して、ProcessBからProcessAへの応答としてメッセージが送信される前に、processAに到着します。
I.どちらのフローはメッセージングのJavaネットワークプログラミングコーディネーション

(1) 
ProcessA ---->(msg)----> ProcessB(PortY) (TCP1) 
ProcessB does processing 
ProcessB(portY)--->(response)----->ProcessA (TCP1) 
ProcessB--->(msg)----->ProcessA(portX) (TCP2) 

(2) 
ProcessA ---->(msg)----> ProcessB(PortY) (TCP1) 
ProcessB does processing 
ProcessB--->(msg)----->ProcessA(portX) (TCP2) 
ProcessB(portY)--->(response)----->ProcessA (TCP1) 

EDIT(EJP要求の後) どのように私は前に、ProcessBはProcessBがProcessAのサーバーportXにオープンクライアントソケットを持っていることを接続を介してMSGを送信しないことを確認してください/強制することができますが発生しますプロセスBのサーバーportYからの応答としてメッセージがprocessAに到着しましたか?私。上記(1)の流れのみを持つこと。
processBはマルチスレッドであり、処理は簡単ではないことに注意してください。

UPDATE: が、それは私の誤解であるかもしれないが、プロセスはソケット経由でデータを送信し、制御がアプリケーションに返されたときに、これは、受信側がデータを受信したことを意味するものではありません。 プロセスが2つのソケットを介してデータを送信する場合、OSによって競合状態はありますか?

アップデート2
答えた後、私はビジェイマシューから得た:提案として、私はロックをした場合
、OS(すなわち、IP層)の順序でデータを送信することを保証するものではあり?私。 1つの送信を終了し、次に送信しますか?あるいは、彼らは多重化され、同じ問題を抱えていますか?

おかげ

+0

これを明確にすることはできますか?以前の*返信がポートXを経由してAから到着するまで、Bが* next *リクエストをportX経由でAに送信してはならないということを意味しますか?したがって、ポートYはここでは完全に無関係ですか? – EJP

+0

@ejp:2つのtcp接続があります。 Bは、Aによって受信された前のメッセージ(ポートYで聞いていたAからBによって送信された)の応答が受信される前に、AにopenされたportX(Aで開かれた)したがって、portYは無関係ではありません。 Aによる最初のmsgが送信されたのはTCP接続です。 – Cratylus

+0

あなたのパラは「どうすれば保証できますか」ではポートYについて言及していません。それで、あなたはちょうど言ったことに同意しない。これらすべてを同意してください。だから私はポートYに何かを送るべきではないということを集めていますが、ポートYには保留中の返事があります。 – EJP

答えて

1

は明白な解決策は次のとおりです。

LockObject lock; 

ProcessA ---->(msg)----> ProcessB(PortY) 

// Processing the request and sending its response 
// makes a single transaction. 
synchronized (lock) { 
    ProcessB does processing 
    ProcessB(portY)--->(response)----->ProcessA (TCP1) 
} 

// While the processing code holds the lock, B is not 
// allowed to send a request to A. 
synchronized (lock) { 
    ProcessB--->(msg)----->ProcessA(portX) (TCP2) 
} 
+0

私が誤解しているかもしれませんが、processBがソケット経由で送信するデータをOSに渡すと、データがもう一方の端で受信された後にOSからアプリケーションに制御が戻ってきますか?いいえ、OSがデータをバッファできるように、ProcessBは2番目のロックに移動して、2番目のソケットでデータを渡します。だから2つの送信の間に、まだいくつかの競合状態が存在するでしょうか? – Cratylus

0

明白な疑問は、なぜあなたは気にしないのですか?どちらの側でも同期が必要な操作がある場合は、その操作を行います。 TCPがあなたのためにそれをすることを期待してはいけません。それはそれが目的ではありません。

+0

どのように同期しますか? – Cratylus

+0

なぜ同期しますか? – EJP

+0

私はあなたが何を示唆しているかわかりません。たとえば、私がビジェイ・マシューの提案に従っているかどうかを知りたいのですが、私はデータが送信される方法の結果として競合状態になります。 OSは両方のデータをバッファして、それらをワイヤで多重化して送信します。 – Cratylus

1

同期の問題はTCPプロトコルではなく、メッセージが到着したときに起きるスレッドを選択するスレッド・ハンドラにあります。 PortY "(Msg)"がPortYの後に非常に迅速に送信されたというあなたの質問の性質から理解しています "(応答)"つまり、スレッドハンドラは、2つのリスニングスレッドのうち、どちらが起きるかを選択することがあります。

問題を解決する簡単ではあるが、醜く不完全な方法は、応答と次のメッセージの間に短いスリープを挿入することです。スリープは、次のメッセージが受信される前に、他のプロセスが応答までに目覚めたことを確信できるほど長くなければなりません。この方法は不完全です。処理を適切に同期させる変更を増やしていても、OSの負荷やネットワークの輻輳などの問題は、常にあなたのメッセージの背後にあなたの応答の背後に押し戻すことができます。そして、あなたはあなたが始めたところに戻ってきました。醜さのもう一つのビットは、睡眠が時間を無駄にし、最大スループットを低下させるということです。ほんの少しだけ。だから...

問題を完全に解決するには、受信したばかりのメッセージが処理される次のメッセージかどうか、または以前のメッセージが処理される必要があるかどうかを各ソケットリスナーが認識する必要があります最初。これは、各プロセスから送信されたすべてのメッセージに順番に番号を付けることで行います。受信プロセスは何かが欠けているかどうかを知る。

受信したメッセージが送信順に処理されるように、各ソケット上のリスナーがそれらの間で協議する方法を考える必要があります。多くの実用的な解決法がありますが、すべて抽象的な概念レベルで同じものになります。

スレッド1: A)ProcessA(PortX)スレッドがメッセージを受信して​​スリープ解除します。
B)シーケンス番号がメッセージの欠落を示す場合は、B1)はProcessA(PortY)とwait()で同期します。 B2)起床時にB)に戻る C){メッセージがありません}メッセージを処理します。 D)A)に戻る

スレッド2: A)ProcessA(PortY)が応答を受信して​​復帰する。 B)応答を処理します。 C)notifyAll()。 D)Back to A)

最も一般的な実用的な解決策は、すべての新しいメッセージをPriorityQueueに追加する単一のソケットリスナーインスタンスを必要とするため、最も早く送信されたメッセージは常にキューの先頭に移動します。スレッド1とスレッド2は、処理できるメッセージが到着するまで、そのインスタンスを待機することができます。

シンプルだが拡張性の低いソリューションは、各スレッドに処理を通知する(応答)ハンドラを使用して待機して待機させることです。

結局のところ、今回は結構ですが、すでに解決済みです。

関連する問題