2011-11-05 5 views
5

Usando un socket de mensajes ZMQ.SocketType.REP (respuesta) con ZeroMQ, recibo mensajes y luego envío un mensaje "OK".ZeroMQ socket Recv() arroja la excepción 'Contexto finalizado': ¿por qué y cómo recuperarlo?

Por ahora, estoy intentando esto localmente (enviando/recibiendo mensajes de la misma aplicación de consola C# ejecutándose en la misma máquina).

con bastante regularidad (después de alrededor de 1500 mensajes), la línea:

var receivedBytes = _recvSocket.Recv();

... será una excepción: Context was terminated

Mi pregunta es, ¿por qué sucede esto, y ¿cómo te recuperas de él?

Tengo un System.Threading.Thread dedicada a la ejecución de mi "del lado del servidor" ZeroMQ responder zócalo, aquí es el bucle que se ejecuta:

private static void MessagingLoopReceive(object state) 
    { 
     if (_zmqc == null) 
     { 
      _zmqc = new ZMQ.Context(1); 
     } 

     _recvSocket = _zmqc.Socket(ZMQ.SocketType.REP); 
     _recvSocket.Bind("tcp://*:5556"); 

     while (true) 
     { 
      if (_queueStop) 
      { 
       break; 
      } 

      //Console.WriteLine("Server blocking for receive..."); 
      var receivedBytes = _recvSocket.Recv(); 

      if (receivedBytes != null && receivedBytes.Length > 0) 
      { 
       //Console.WriteLine("Server message received from client, sending OK"); 
       _recvSocket.Send("OK", Encoding.ASCII); 
       //Console.WriteLine("Server OK sent, adding message to queue"); 
       _queuedMessages.Enqueue(receivedBytes); 
      } 
      else 
      { 
       Thread.Sleep(1); 
      } 
     } 
    } 

Respuesta

7

significa que alguien (el recolector de basura?) Han cerrado el contexto .

+0

Tiene razón: el contexto se configuró de manera que el GC estaba interfiriendo con él. ¡¡Gracias!! – Brandon

+0

¿Podrías por favor dar más detalles sobre esto? – Sergejus

+0

Una alternativa es usar 'GC.KeepAlive': http://msdn.microsoft.com/en-us/library/system.gc.keepalive(v=vs.90).aspx para evitar la recolección de basura en el objeto. –

0

Agregando esta respuesta para completarla.

if (_zmqc == null) 
    { 
     _zmqc = new ZMQ.Context(1); 
    } 
    _recvSocket = _zmqc.Socket(ZMQ.SocketType.REP); 

Este es el único lugar donde se utiliza el contexto _zmqc. Por lo tanto, el GC lo ve como un candidato potencial para la limpieza. Una vez que lo esté, se le llama a disponer. Esto obligará a todos los sockets a terminar con un número de error ETERM de ZMQ.

Lo primero que se debe hacer es usar una cláusula using en la que el contexto necesita mantenerse vivo. Esto forzará al GC a dejar el objeto solo.

Luego, al cerrar el ciclo, debe detectar la excepción, ver que es un número de error ETERM y luego salir con gracia.

try 
{ 
    //Any ZMQ socket sending or receiving 
} 
catch (Exception e) 
{ 
    if (e.Errno == ETERM) 
    { 
     //Catch a termination error. 
     break; // or return, or end your loop 
    } 
} 

Enjoy!

Edit: Casi olvidado los números de error en ZMQ son "de lujo", el primero comienza en 156384712 y suben. ETERM es 156384712 + 53. Sin embargo, solo el doco ya que esto puede haber cambiado desde la escritura.

Cuestiones relacionadas