Pergunta

Eu estou projetando uma aplicação de chat cliente-servidor (na verdade eu não sou, mas vamos fingir que eu sou :)), e eu estou um pouco confuso por algumas condições de corrida eu experimentei.

Vamos dizer que tenho o seguinte código:

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

E aqui está um trecho da configuração de ligação:

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

Este é, naturalmente, algum tipo de pseudo c #, eu removi um monte de código não relevantes para a causa clareza.

Agora ao ponto: Este código não vai funcionar. Quando eu chamar BroadcastMessage, o método nunca retorna, e eu, eventualmente, obter um tempo limite no lado do cliente. Se eu depuração no lado do servidor, tudo parece bem (eu voltar a partir do método BroadcastMessage exatamente como seria de esperar, e eu não estou de bloqueio em todas as chamadas ReceiveMessage só ida)

Aqui estão duas maneiras de corrigir este código:

  1. remover o FaultContract e declarar o método BroadcastMessage como oneway = true
  2. Transmissão a mensagem para todos, mas o remetente inicial

Minha primeira suposição era de que lado do cliente estava esperando pelo servidor para retorno, e, portanto, não estava disponível para lidar com a chamada ReceiveMessage de entrada do servidor, bloqueando assim o servidor, mas ReceiveMessage é declarado como oneway e depuração do shows de servidor que não bloqueiam em qualquer chamada para ReceiveMessage

Agora, a minha pergunta:

  • O que está acontecendo?

  • Existem outras maneiras de corrigir isso? (Talvez por meio do ajuste da configuração de ligação?)

  • Digamos que eu escolher correção 2 (ou seja, não transmitem de volta para o remetente), o que acontece se o servidor chama o meu retorno ReceiveMessage (porque alguém me enviou uma mensagem) enquanto eu estou esperando por minha própria BroadcastMessage chamada ao fim?

  • Eu li que as chamadas Oneway não são totalmente de sentido único, e que o servidor ainda espera por uma resposta de HTTP a partir do outro lado. Todos os detalhes sobre este assunto? Especificamente, é o cliente capazes de responder suche http respostas quando está bloqueado em uma chamada distante?

Edit: Console NET 3.5 no lado do servidor, WinForms NET 3.5 no lado do cliente

Foi útil?

Solução

Parece um impasse, talvez devido ao sincronismo de contexto. O que é o cliente? Winform? WPF? WCF aspectos de sincronização ao contexto, o que significa "mudar para o segmento UI" para winforms e WPF. Se você é fazer a solicitação de bloqueio no segmento interface do usuário, em seguida, ao longo do jogo.

Tente realizar sua solicitação WCF em uma discussão de fundo, de modo que o segmento interface do usuário está disponível para atender a solicitação de entrada; Isto poderia ser tão simples quanto usar ThreadPool, ou talvez BackgroundWorker.

Outras dicas

tente adicionar esse atributo para a sua implementação concreta do seu serviço:

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

Em segundo lugar, tente ligar WCF de rastreamento para ver se você tem algo acontecendo nas entranhas da sua implementação WCF que está dando o seu sofrimento. Eu tive alguns erros muito estranho que só faziam sentido quando fui para rastreamento e descobriu que a mensagem de erro real que foi ocorrendo.

Tracing um serviço WCF

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top