2009-01-23 8 views
2

Je concevais une application de chat client-serveur (en fait je ne suis pas, mais prétendons que je suis :)), et je suis un peu déconcerté par certaines conditions de course J'ai expérimenté.conditions de course dans WCF avec des méthodes non-oneway

Disons que j'ai le code suivant:

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

Et voici un extrait de la configuration de liaison:

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

Ceci est bien sûr une sorte de pseudo C#, je Nous avons supprimé beaucoup de code non pertinent pour des raisons de clarté.

Maintenant au point: Ce code ne fonctionnera pas. Lorsque j'appelle BroadcastMessage, la méthode ne revient jamais et j'obtiens finalement un délai d'expiration côté client. Si je débogue sur le côté serveur, tout semble bien (je reviens de la méthode BroadcastMessage exactement comme on s'y attend, et je ne bloque pas sur les appels unidirectionnels ReceiveMessage)

Voici deux façons de corriger ce code:

  1. retirer le FaultContract et déclarer la méthode BroadcastMessage comme oneway = true
  2. diffusion du message à tout le monde, mais l'expéditeur initial

Ma première hypothèse est que le côté client attendait le serveur revenir , et n'était donc pas disponible pour gérer l'appel entrant ReceiveMessage du serveur, bloquant ainsi le serveur, BUT ReceiveMessage est déclaré comme unway, et le débogage du serveur montre qu'il ne bloque pas sur un appel à ReceiveMessage

Maintenant , mes questions:

  • Que se passe-t-il?

  • Y a-t-il d'autres moyens de résoudre ce problème? (Peut-être en réglant la configuration de liaison?)

  • Disons que je choisis fix 2 (ie ne diffuse pas à l'expéditeur), ce qui se passe si le serveur appelle mon rappel ReceiveMessage (parce que quelqu'un d'autre m'a envoyé un message) pendant que j'attends que mon propre appel BroadcastMessage se termine? J'ai lu que les appels OneWay ne sont pas totalement unilatéraux, et que le serveur attend toujours une réponse HTTP de l'autre côté. Des détails à ce sujet? Plus précisément, le client est-il capable de répondre aux réponses HTTP lorsque celles-ci sont bloquées dans un appel distant?

Edit: Console .net 3.5 sur le côté serveur, Winforms 3.5 .net sur le côté client

Répondre

2

Cela ressemble à une impasse, peut-être en raison de la synchronisation contexte. Quel est le client? Winform? WPF? WCF respecte le contexte de synchronisation, ce qui signifie "passer au thread d'interface utilisateur" pour Winforms et WPF. Si vous êtes en faisant la demande de blocage sur le thread UI, puis jeu terminé.Essayez d'exécuter votre requête WCF sur un thread d'arrière-plan, afin que le thread d'interface utilisateur soit disponible pour traiter la demande entrante; cela pourrait être aussi simple que d'utiliser ThreadPool, ou peut-être BackgroundWorker.

+0

En effet, je fais mon appel de l'interface utilisateur Thread.I'll essayer inovking sur l'autre. Pourtant, je ne comprends pas pourquoi l'impasse se produit. Le serveur ne devrait pas attendre que le client réponde, devrait-il? Pourriez-vous être plus précis sur ce qui se passe derrière la scène ici? Merci beaucoup! – Brann

+0

Vous avez un sens = faux ... donc * devrait * attendre. –

+0

Invoquer à partir d'un autre thread a résolu le problème! :) – Brann

1

essayer d'ajouter cet attribut à votre mise en œuvre concrète de votre service:

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

En second lieu, essayez de le WCF calque pour voir si vous avez quelque chose qui se passe dans les entrailles de votre mise en œuvre de WCF qui donne votre douleur. J'ai eu quelques erreurs vraiment bizarres qui n'ont de sens que lorsque je suis entré dans le traçage et j'ai découvert le message d'erreur ACTUAL qui se produisait.

Tracing a WCF Service

+0

Malheureusement, l'ajout de cet attribut n'a pas résolu le problème. Pourtant, ça valait la peine d'essayer! Merci:) – Brann

Questions connexes