2

私はクライアントサーバーチャットアプリケーションを設計しています(実際はそうではありませんが、私がそうであるふりをしましょう:))、そして私は私が経験したいくつかの競合状態に少し戸惑っています。

次のコードがあるとしましょう。

public interface IServer
{
  [OperationContract(IsOneWay = false)]
  [FaultContract(typeof(ChatException))]
  void BroadcastMessage(string msg);
}

public class Server : IServer 
{
  void BroadcastMessage(string msg) // I'm not mentionning the try/catch/throw FaultException here for readability purposes
  {
    foreach (IClientCallback c in callbacks){
      c.ReceiveMessage(msg);
    }

  }
}

public interface IClientCallback
{
  [OperationContract(IsOneWay = true)]
  void ReceiveMessage(string s);
}

そして、ここにバインディング構成の抜粋があります:

<endpoint address="" 
binding="netTcpBinding" 
bindingConfiguration="DuplexBinding" 
contract="IServer" />

 <binding name="DuplexBinding" sendTimeout="00:01:00">
   <reliableSession ordered="true" inactivityTimeout="00:05:00" enabled="true"/>
   <security mode="None">
     <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
     <message clientCredentialType="Windows" />
   </security>
 </binding>

これはもちろん、ある種の疑似c#です。わかりやすくするために、関連性のないコードをたくさん削除しました。

要点:このコードは機能しません。BroadcastMessageを呼び出すと、メソッドが返されることはなく、最終的にクライアント側でタイムアウトが発生します。サーバー側でデバッグすると、すべてが正常に見えます(BroadcastMessageメソッドから期待どおりに戻り、ReceiveMessageの片道呼び出しをブロックしていません)

このコードを修正する2つの方法があります:

  1. FaultContractを削除し、BroadcastMessageメソッドをoneway=trueとして宣言します
  2. メッセージを全員にブロードキャストしますが、最初の送信者

私の最初の推測では、クライアント側はサーバーが戻るのを待っていたため、サーバーからの着信ReceiveMessage呼び出しを処理できなかったため、サーバーがブロックされましたが、ReceiveMessageは一方向として宣言され、サーバーをデバッグすると次のようになります。 ReceiveMessageへの呼び出しをブロックしません

さて、私の質問:

  • どうしたの?

  • これを修正する他の方法はありますか?(おそらくバインディング構成を調整することによって?)

  • 修正2を選択したとしましょう(つまり、送信者にブロードキャストしないでください)。自分のBroadcastMessage呼び出しが終了するのを待っている間に、サーバーがReceiveMessageコールバックを呼び出した場合(他の誰かが私にメッセージを送信したため)はどうなりますか?

  • OneWay呼び出しは完全に一方向ではなく、サーバーはまだ反対側からのHTTP応答を待機していることを読みました。これについての詳細はありますか?具体的には、クライアントは、遠隔通話でブロックされたときに、そのようなhttp応答に応答できますか?

編集:サーバー側でConsole .net 3.5、クライアント側でWinforms .net 3.5

4

2 に答える 2

2

おそらくsync-contextが原因で、デッドロックのように聞こえます。クライアントは何ですか?Winform?WPF?WCFはsync-contextを尊重します。これは、winformsとWPFの「UIスレッドに切り替える」ことを意味します。UIスレッドでブロック要求を行っている場合は、ゲームオーバーです。

バックグラウンドスレッドでWCF要求を実行してみて、UIスレッドが着信要求を処理できるようにします。ThreadPoolこれは、、または多分を使用するのと同じくらい簡単かもしれませんBackgroundWorker

于 2009-01-23T09:32:29.617 に答える
1

この属性をサービスの具体的な実装に追加してみてください。

[System.ServiceModel.ServiceBehavior(UseSynchronizationContext=false)]
public class Server : IServer {}

次に、WCF トレースをオンにして、WCF 実装の内部で問題が発生していないかどうかを確認してください。私は本当に奇妙なエラーがいくつかありましたが、それはトレースに入って実際に発生していたエラー メッセージを見つけたときにのみ意味をなすものでした。

WCF サービスのトレース

于 2009-01-23T10:07:36.753 に答える