ZeroMQ socket Recv () выбрасывает исключение «Контекст был прерван» - зачем и как восстанавливать? - PullRequest
5 голосов
/ 05 ноября 2011

Используя сокет обмена сообщениями ZMQ.SocketType.REP (ответ) с ZeroMQ, я получаю сообщения, а затем отправляю сообщение "OK" обратно.

Сейчас я пытаюсь это сделать локально (отправка / получение сообщений из того же консольного приложения C #, работающего на той же машине).

Довольно регулярно (примерно через 1500 сообщений), строка:

var receivedBytes = _recvSocket.Recv();

... сгенерирует исключение: Context was terminated

У меня вопрос: почему это происходит, и как вы восстанавливаетесь после него ?

У меня есть System.Threading.Thread, предназначенный для запуска моего "серверного" сокета ответа ZeroMQ, вот цикл, который он запускает:

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

Ответы [ 2 ]

7 голосов
/ 05 ноября 2011

Это означает, что кто-то (сборщик мусора?) Закрыл контекст.

0 голосов
/ 07 сентября 2012

Добавление этого ответа для полноты.

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

Это единственное место, где используется контекст _zmqc.Поэтому GC рассматривает его как потенциального кандидата для очистки.Как только это произойдет, распоряжение вызывается на нем.Это заставит все сокеты завершиться с номером ошибки ETERM от ZMQ.

Первое, что нужно сделать, это использовать предложение using, где контекст должен остаться в живых.Это заставит GC оставить объект в покое.

Далее при закрытии цикла необходимо отловить исключение, увидеть, что это номер ошибки ETERM, и затем корректно завершить работу.

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

Наслаждайтесь!

Редактировать: Почти забытые номера ошибок в ZMQ "причудливы", первый начинается с 156384712 и идет вверх.ETERM - 156384712 + 53. Однако только документ, как это могло измениться с момента написания.

...