2009-12-07 13 views
7

Quiero crear un ejemplo simple de cliente-servidor en WCF. Hice algunas pruebas con devoluciones de llamadas, y funciona bien hasta el momento. Jugué un poco con la siguiente interfaz:WCF - Devolución de llamada del cliente frente a sondeo para "mantener la lista de suscriptores"

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IStringCallback))] 
public interface ISubscribeableService 
{ 
    [OperationContract] 
    void ExecuteStringCallBack(string value); 

    [OperationContract] 
    ServerInformation Subscribe(ClientInformation c); 

    [OperationContract] 
    ServerInformation Unsubscribe(ClientInformation c); 
} 

Es un ejemplo simple. un poco ajustado. Puede solicitar al servidor que "ejecute una devolución de llamada por secuencias", en cuyo caso el servidor invierte la cadena y llama a todas las devoluciones de llamada de los clientes suscritas.

Ahora, aquí viene la pregunta: si quiero implementar un sistema donde todos los clientes "se registran" con el servidor, y el servidor puede "preguntar" a los clientes si todavía están vivos, ¿implementaría esto con devoluciones de llamada (así que en lugar de este "stringcallback" una especie de TellTheClientThatIAmStillHereCallback). Al verificar el estado de comunicación en la devolución de llamada también puedo "saber" si un cliente está muerto. Algo similar a esto:

Subscribers.ForEach(delegate(IStringCallback callback) 
        { 
         if (((ICommunicationObject)callback).State == CommunicationState.Opened) 
         { 
          callback.StringCallbackFunction(new string(retVal)); 
         } 
         else 
         { 
          Subscribers.Remove(callback); 
         } 
        }); 

Mi problema, dicho de otro modo:

  • el servidor puede tener 3 clientes
  • Cliente A muere (me tire de la clavija de la computadora portátil)
  • el servidor muere y vuelve a la línea
  • Un nuevo cliente llega hasta

Entonces, básicamente, ¿usaría devoluciones de llamada para verificar el "estado de vida inmóvil" de los clientes, o usaría sondeos y realizar un seguimiento "cuánto tiempo no he oído hablar de un cliente" ...

+0

¿Cómo se está conectando al WCF Sever? ¿Estás usando TCP? Eso cambiaría la forma de implementar un agrupamiento. –

Respuesta

0

Tuve una situación similar usando WCF y devoluciones de llamada. No quería usar el sondeo, pero estaba usando un protocolo "reilable", por lo que si un cliente moría, colgaría el servidor hasta que se agotara el tiempo de espera y se bloqueara.

No sé si esta es la solución más correcta o más elegante, pero lo que hice fue crear una clase en el servicio para representar al proxy del cliente. Cada instancia de esta clase contenía una referencia al proxy del cliente y ejecutaba la función de devolución de llamada cada vez que el servidor configuraba la propiedad "mensaje" de la clase. Al hacer esto, cuando un cliente se desconecta, la clase contenedora individual obtiene la excetción de tiempo de espera y se elimina de la lista de oyentes del servidor, pero el servicio no debería esperar. Esto en realidad no responde a su pregunta sobre si el cliente está vivo, pero es otra forma de estructurar el servicio para resolver el problema. Si necesitara saber cuándo murió un cliente, podrá retomarlo cuando el envoltorio del cliente se elimine de la lista de oyentes.

0

No he tratado de utilizar devoluciones de llamada WCF a través del cable, pero los he usado para la comunicación entre procesos. Estaba teniendo un problema por el cual la llamada de las llamadas que se estaban enviando terminaba en el mismo hilo y hacía que el servicio se bloqueara cuando había llamadas que dependían del mismo hilo.

Esto puede aplicarse al problema que tiene actualmente así que esto es lo que tuve que hacer para solucionar el problema.

poner este atributo en el servidor y el cliente de la clase Implementación del servidor de WCF

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class WCFServerClass 

El ConcurrencyMode.Multiple hace que cada proceso de llamada en su propio hilo que se debe ayudar con el servidor de bloqueo cuando un cliente muere hasta que se agote el tiempo.

También se aseguró de utilizar un grupo de subprocesos en el lado del cliente para asegurarse de que no había problemas de threads en el lado del cliente

3

Puede detectar la mayoría de los cambios en el estado de la conexión a través de la Closed, Closing, y Faulted eventos de ICommunicationObject. Puede conectarlos al mismo tiempo que configura la devolución de llamada. Esto es definitivamente mejor que las encuestas.

IIRC, el evento Faulted solo disparará después de que realmente intenta utilizar la devolución de llamada (sin éxito). Entonces, si el Cliente simplemente desaparece, por ejemplo, un reinicio o apagado forzoso, no se lo notificará de inmediato. ¿Pero necesitas serlo? Y si es así, ¿por qué?

Una devolución de llamada de WCF puede fallar en cualquier momento, y siempre debe tener esto en el fondo de su mente. Incluso si tanto el cliente como el servidor están en buen estado, es posible que termine con un canal con fallas debido a una excepción o una interrupción de la red. O tal vez el cliente se desconectó en algún momento entre su última encuesta y su operación actual. El punto es que, mientras codifiques tus operaciones de devolución de llamada de forma defensiva (lo cual es una buena práctica de todos modos), en general, conectar los eventos anteriores es suficiente para la mayoría de los diseños. Si se produce un error por cualquier motivo, incluido un cliente que no responde, el evento Faulted se activará y ejecutará su código de limpieza.

Esto es a lo que me referiría como el enfoque pasivo/perezoso y requiere menos codificación y chat en la red que los métodos de sondeo o mantenimiento.

+0

Esto es lo que he hecho cada vez que he necesitado una funcionalidad similar (que es algo frecuente). – kyoryu

2

Si habilita las sesiones fiables, WCF mantiene internamente un mecanismo de control de mantener vivo. Comprueba regularmente, a través de mensajes de prueba de infraestructura oculta, si el otro extremo todavía está allí. El intervalo de tiempo de estas comprobaciones puede verse influido a través de la propiedad ReliableSession.InactivityTimeout. Si establece la propiedad en, por ejemplo, 20 segundos, el evento ICommunicationObject.Faulted se generará entre 20 y 30 (máximo) segundos después de que se haya producido una falla en el servicio en el otro lado.

Si desea asegurarse de que las aplicaciones cliente siempre permanezcan "conectadas automáticamente", incluso después de interrupciones temporales del servicio, puede utilizar un hilo de trabajo (del grupo de subprocesos) que intenta repetidamente crear una nueva instancia de proxy en el lado del cliente, y llama a una operación de inicio de sesión, después de que el evento Faulted se haya levantado allí.

Como segunda aproximación, dado que está implementando un mecanismo de subprocesos de trabajo de todos modos, también puede ignorar el evento Faulted y permitir al trabajador enrutar durante toda la vida útil de la aplicación cliente. Deje que el hilo compruebe repetidamente el estado del proxy, y trate de hacer su trabajo de reparación cada vez que el estado tenga una falla.

Usando la primera o la segunda aproximación, puede implementar una arquitectura de bus de servicio (patrón de mediador), garantizando que todas las instancias de aplicaciones cliente estén constantemente listas para recibir mensajes de servicio "espontáneos" cada vez que se esté ejecutando el servicio.

Por supuesto, esto sólo funciona si la sesión fiable "como tal" está configurado correctamente para empezar (utilizando una sesión con capacidad de unión, y la aplicación de la ServiceContractAttribute.SessionMode, ServiceBehaviorAttribute.InstanceContextMode, OperationContractAttribute.IsInitiating y OperationContractAttribute. IsTerminating propiedades de manera significativa).

Cuestiones relacionadas