0

Windows Phone 7 アプリケーションで疑似同期ソケットを使用しています。私のソケット コードはhttp://msdn.microsoft.com/en-us/library/hh202858(v=vs.92).aspxのサンプルに基づいています。

サーバーの送信パターンはやや予測不能です。メッセージの残りの長さを含む固定サイズのヘッダーで始まります。最初にこのヘッダーを読み取り、次に指定されたバイト数をソケットから読み取りました。

サーバーにもメッセージを送信する必要があり、受信用のスレッドと送信用の別のスレッドでソケットを二重化しようとすると、多くの問題が発生したため、コードに次のようなループがあります。

while (KeepConnectionGoing)
        {
            byte[] Rcvd;
            Rcvd = Socket.Receive();//Returns null if no message received in 50 ms
            if (Rcvd != null)
            {
                ParseMessage(Rcvd);
            }

            if (HasMessageThatNeedsToBeSent())
            {
                byte[] Message = GetMessageToSend();
                Socket.Send(Message);
            }
        }

これはほとんどの場合問題なく動作しますが、メッセージが null の場合に奇妙なことが起こります。Receive メソッドのタイムアウト (リンクされたサンプルを参照) は ManualResetEvent を使用するため、ソケットの受信要求が実際にキャンセルされることはありません。メソッドが戻ったとしても、そのリクエストはどこかで待機し、ソケットでデータが利用可能になると、ヘッダーをむさぼり食います。イベント ハンドラーは、受信したデータとは何の関係もありません (メソッドが返され、メソッド内の変数が再び使用されることはないため)、データは基本的に消えます。ヘッダースキップを返すと予想される読み取り要求は、ヘッダーの後のバイトを読み取ります。メッセージの長さはわかりません。

ソケットがタイムアウトした場合、未処理のリクエストをすべてキャンセルできるようにしたいと考えています。サンプルのような匿名メソッドを使用しています。これにより、すべてが簡素化され、すべての状態転送コードを自分で記述する必要がなくなります。したがって、イベント ハンドラーをアンフックできません。ただし、メソッドをイベント ハンドラーとして使用していたとしても、非同期操作が完了する前にフックを解除しても、コールバック メソッドが呼び出されると思います。(私はこれをテストしていません、それは私の理解です)

現在、私が見ることができる唯一の解決策は、いくつかの静的なバイト配列をハッキングすることです (つまり、静的な byte[] ヘッダーを持ち、それが null の場合はヘッダーを読み取り、それ以外の場合はメッセージを読み取ります) が、それは本当に洗練されていないソリューションであり、競合状態になりがちです。

より良い方法はありますか?

ありがとう

4

1 に答える 1

0

これを行う良い方法は本当にないようです。poll メソッドがあれば便利ですが、Silverlight にはありません。私は静的フラグを使用して解決策をハックし、現在の状態 (ヘッダーが要求されているか、メッセージが要求されているか)、長さの静的 int、および静的バッファーを教えてくれました。

メソッドの開始時に、ヘッダーまたはボディのいずれかを要求できます。ヘッダーが既に要求されている場合、スレッドは有効な本文の長さが利用可能になるまで待機します。この待機がタイムアウトした場合は、ヘッダーの受信操作がまだ保留中であることを意味しますが、実際には使用できるメッセージがありません。それ以外の場合は、その長さのメッセージを読み取ります。

ヘッダーが要求されていない場合は、ヘッダーを受け取ります。イベント ハンドラーでは、完了後に、制御フローが既に続行されているかどうかを確認します (つまり、受信操作に時間がかかりすぎたため、関数は既に返されましたが、実際には完了しています)。長さを更新してから、タイムアウトしない限り本文を要求します。

于 2012-08-14T23:48:24.270 に答える