简体   繁体   English

ZeroMQ socket Recv()抛出'Context is terminated'异常 - 为什么以及如何恢复?

[英]ZeroMQ socket Recv() throws 'Context was terminated' exception - why and how to recover?

Using a ZMQ.SocketType.REP (reply) messaging socket with ZeroMQ, I am receiving messages and then sending an "OK" message back. 使用带有ZeroMQ的ZMQ.SocketType.REP (回复)消息传递套接字,我正在接收消息,然后发回“OK”消息。

For now, I'm trying this locally (sending/receiving messages from the same C# console app running on the same machine). 现在,我正在本地尝试(从同一台机器上运行的同一个C#控制台应用程序发送/接收消息)。

Fairly regularly (after about 1500 messages), the line: 相当经常(大约1500条消息后),该行:

var receivedBytes = _recvSocket.Recv();

... will throw an exception: Context was terminated ...将抛出异常: Context was terminated

My question is, why does this happen, and how do you recover from it ? 我的问题是, 为什么会发生这种情况, 你如何从中恢复

I have a System.Threading.Thread dedicated to running my "server-side" ZeroMQ reply socket, here is the loop that it runs: 我有一个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);
            }
        }
    }

这意味着有人(垃圾收集器?)关闭了上下文。

Adding this answer for completeness. 添加此答案是为了完整性。

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

This is the only place the context _zmqc is used. 这是使用上下文_zmqc的唯一位置。 Therefore the GC sees it as a potential candidate for cleaning up. 因此,GC认为它是清理的潜在候选人。 Once it is, dispose is called on it. 一旦它,就会调用dispose。 This will then force all sockets to terminate with a ETERM error number from ZMQ. 然后,这将强制所有套接字以ZMQ中的ETERM错误号终止。

The first thing that needs to be done is use a using clause around where the context needs to stay alive. 首先需要做的是在上下文需要保持活动的地方使用using子句。 This will force the GC to leave the object alone. 这将强制GC单独留下对象。

Next when closing down the loop you need to catch the exception see that its a ETERM error number and then exit gracefully. 接下来关闭循环时,您需要捕获异常,看看它是一个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 
    }
}

Enjoy! 请享用!

Edit: Almost forgot error numbers in ZMQ are "fancy" the first one starts at 156384712 and they go up. 编辑:几乎忘了ZMQ中的错误数字是“花哨的”第一个从156384712开始并且它们上升。 ETERM is 156384712 + 53. However just the doco as this may have changed since writing. ETERM是156384712 + 53.然而,自从写作以来,这可能已经改变了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM