HTTPポーリングデュプレックスWCFチャネルを使用してTomekJanczukのPub/subサンプルを追跡しましたが、クライアントがブラウザーを閉じて切断すると、サービスが次のコールバックで通知しないことに気付きました。エンドポイントがもう存在しないという例外などを期待していました。
クライアントへの公開を停止するために、クライアントがいつなくなったかをどのように知ることができますか?
HTTPポーリングデュプレックスWCFチャネルを使用してTomekJanczukのPub/subサンプルを追跡しましたが、クライアントがブラウザーを閉じて切断すると、サービスが次のコールバックで通知しないことに気付きました。エンドポイントがもう存在しないという例外などを期待していました。
クライアントへの公開を停止するために、クライアントがいつなくなったかをどのように知ることができますか?
確実に知るために:不可能。
TCP接続が閉じられると(HTTP呼び出しの基礎となる)、特別なTCPメッセージがサーバーに送信されます(FINパケット)。HTTPはステートレスですが、基盤となるTCP接続はステートフルであり、キープアライブを備えていますが、基盤となるTCP接続は通常開いたままです。クライアントが破棄されると、TCP接続が閉じられ、通常はサーバーにメッセージが送信されます。ただし、クラッシュしたり、ネットワークが切断されたりした場合は、これを行う時間がありません。つまり、一言で言えば、あなたは決して確信することはできません。
詳細については、こちらをご覧ください。
単純な解決策ではありますが、不十分な解決策が1つあるようです。クライアントのコールバックがタイムアウトした場合は、再度呼び出さないでください。
私のシステムでは、手動の「チェック」呼び出しも実装しました。サーバーは、 n秒ごとに、登録された各クライアントのコールバックチャネルを介してパラメーターなしのメソッドを呼び出し、クライアントがまだ存在するかどうかを確認します。それが本当に良い考えだったかどうか疑問に思い始めています-デバッガーでクライアントを一時停止したためにコールバックタイムアウトが発生し続けるという新しい問題が発生しました。
その難しい、ほとんど不可能(SLデュプレックス機能が制限されているため)。サービスにユーザーのリストを実装し、プロパティ「IsDisconnected」とLastCommunicationTimeを追加しました。これは、WCFサービスがユーザーのOutgoing-Message-Queueにメッセージを追加しようとしたときにタイムアウトになり、失敗して例外をスローした場合です。タイムアウトの。「IsDisconnecte=true」とマークし、次回はそのユーザーにメッセージを送信しようとしないでください。
別のスレッドはそれを監視し続け、LastCommunicationTimeがtimeの値を超えており、IsDisconnected = trueであることに気付いた場合、同じユーザーがこの期間内に再度接続を試みない限り、リストからユーザーを削除します( UserIdで識別します)。
この問題を処理するために手動で行ったことが非常に多いため、WCFサービスが非常にビジーになりました。
私はこの問題に直面し、次のコードで切断されたクライアントを削除するスレッドを作成しました。正常に動作しますが、切断されたクライアントを10〜15分後にクライアントリストから削除します(これは私にとっては問題ありませんでした)。
new Thread(new ThreadStart(() =>
{
while (SilverlightClients != null)
{
lock (SilverlightClients)
{
SilverlightClients = SilverlightClients.Where(d => (d.Callback as IContextChannel).State != CommunicationState.Opened).ToList();
}
Thread.Sleep(1000);
}
})) { Name = "Thread Remove Disconnected Clients" }.Start();