Domanda

Sto progettando un'applicazione di chat client-server (in effetti non lo sono, ma facciamo finta di essere :)), e sono un po 'perplesso dalle condizioni di gara che ho riscontrato.

Diciamo che ho il seguente codice:

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);
}

Ed ecco un estratto della configurazione dell'associazione:

<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>

Questa è ovviamente una specie di pseudo c #, ho rimosso un sacco di codice non pertinente per motivi di chiarezza.

Ora al punto: Questo codice non funzionerà. Quando chiamo BroadcastMessage, il metodo non ritorna mai e alla fine ottengo un timeout sul lato client. Se eseguo il debug sul lato server, tutto sembra a posto (ritorno dal metodo BroadcastMessage esattamente come ci si aspetterebbe, e non sto bloccando nessuna chiamata a senso unico di RiceviMessaggio)

Ecco due modi per correggere questo codice:

  1. rimuovi FaultContract e dichiara il metodo BroadcastMessage come oneway = true
  2. Trasmetti il ??messaggio a tutti MA al mittente iniziale

La mia prima ipotesi è stata che il lato client era in attesa che il server tornasse, e quindi non era disponibile per gestire la chiamata in ricezione di RiceviMessage dal server, bloccando così il server, MA ReceiveMessage è dichiarato a senso unico e il debug del il server mostra che non si blocca su nessuna chiamata a ReceiveMessage

Ora, le mie domande:

  • Cosa sta succedendo?

  • Ci sono altri modi per risolvere questo problema? (forse ottimizzando la configurazione dell'associazione?)

  • Diciamo che ho scelto la correzione 2 (cioè non ritrasmesso al mittente), cosa succede se il server chiama il mio callback di Ricevi messaggi (perché qualcun altro mi ha inviato un messaggio) mentre aspetto il mio Chiamata BroadcastMessage per terminare?

  • Ho letto che le chiamate OneWay non sono totalmente a senso unico e che il server attende ancora una risposta HTTP dall'altra parte. Qualche dettaglio su questo? in particolare, il client è in grado di rispondere a tali risposte http quando viene bloccato in una chiamata distante?

Modifica: Console .net 3.5 sul lato server, Winforms .net 3.5 sul lato client

È stato utile?

Soluzione

It sounds like a deadlock, perhaps due to the sync-context. What is the client? Winform? WPF? WCF respects sync-context, which means "switch to the UI thread" for winforms and WPF. If you are making the blocking request on the UI thread, then game over.

Try performing your WCF request on a background thread, so that the UI thread is available to service the incoming request; this could be as simple as using ThreadPool, or maybe BackgroundWorker.

Altri suggerimenti

try adding this attribute to your concrete implementation of your service:

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

Secondly, try turning on WCF tracing to see if you have something happening in the bowels of your WCF implementation which is giving your grief. I've had some really weird errors which only made sense when I went into tracing and found out the ACTUAL error message that was occuring.

Tracing a WCF Service

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top