Pregunta

Estoy diseñando una aplicación de chat cliente-servidor (de hecho no lo estoy, pero supongamos que sí :)), y estoy un poco desconcertado por algunas condiciones de carrera que he experimentado.

Digamos que tengo el siguiente 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);
}

Y aquí hay un extracto de la configuración de enlace:

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

Esto es, por supuesto, una especie de pseudo c #, he eliminado una gran cantidad de código no relevante por razones de claridad.

Ahora al punto: Este código no funcionará. Cuando llamo a BroadcastMessage, el método nunca regresa, y finalmente obtengo un tiempo de espera en el lado del cliente. Si depuro en el lado del servidor, todo parece estar bien (regreso del método BroadcastMessage exactamente como uno esperaría, y no estoy bloqueando ninguna llamada unidireccional de Recibir Mensaje)

Aquí hay dos formas de arreglar este código:

  1. elimine FaultContract y declare el método BroadcastMessage como oneway = true
  2. Transmite el mensaje a todos, PERO al remitente inicial

Mi primera suposición fue que el lado del cliente estaba esperando que el servidor regresara y, por lo tanto, no estaba disponible para manejar la llamada entrante Recibir mensaje del servidor, bloqueando el servidor, PERO Recibir mensaje se declara como unidireccional y depurar el el servidor muestra que no bloquea ninguna llamada a ReceiveMessage

Ahora, mis preguntas:

  • ¿Qué está pasando?

  • ¿Hay otras formas de arreglar esto? (¿tal vez ajustando la configuración de enlace?)

  • Digamos que elijo la solución 2 (es decir, no transmitir de nuevo al remitente), ¿qué sucede si el servidor llama a mi devolución de llamada de Recibir mensaje (porque alguien más me envió un mensaje) mientras estoy esperando el mío? Llamada BroadcastMessage para finalizar?

  • He leído que las llamadas OneWay no son totalmente unidireccionales, y que el servidor todavía espera una respuesta HTTP del otro lado. ¿Algún detalle sobre esto? específicamente, ¿es capaz el cliente de responder respuestas suche http cuando está bloqueado en una llamada distante?

Editar: Consola .net 3.5 en el lado del servidor, Winforms .net 3.5 en el lado del cliente

¿Fue útil?

Solución

Suena como un punto muerto, quizás debido al contexto de sincronización. ¿Qué es el cliente? Winform? WPF? WCF respeta el contexto de sincronización, que significa "cambiar al hilo de la interfaz de usuario" para winforms y WPF. Si está haciendo la solicitud de bloqueo en el hilo de la interfaz de usuario, entonces el juego ha terminado.

Intente realizar su solicitud WCF en un subproceso en segundo plano, de modo que el subproceso de la interfaz de usuario esté disponible para atender la solicitud entrante; esto podría ser tan simple como usar ThreadPool , o tal vez BackgroundWorker .

Otros consejos

intente agregar este atributo a su implementación concreta de su servicio:

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

En segundo lugar, intente activar el rastreo de WCF para ver si algo sucede en las entrañas de su implementación de WCF que le está causando dolor. He tenido algunos errores realmente extraños que solo tenían sentido cuando comencé a rastrear y descubrí el mensaje de error REAL que estaba ocurriendo.

Seguimiento de un servicio WCF

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top