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

本文关键字:为什么 何恢复 恢复 Recv socket 抛出 ZeroMQ 异常 | 更新日期: 2023-09-27 18:13:33

使用带有ZeroMQ的ZMQ.SocketType.REP (reply)消息套接字,我正在接收消息,然后发送一个"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);
            }
        }
    }

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

表示有人(垃圾收集器?)关闭了上下文

为完整性添加此答案。

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

这是唯一使用context _zmqc的地方。因此,GC将其视为清理的潜在候选者。一旦它存在,就会对它调用dispose。这将迫使所有套接字以来自ZMQ的ETERM错误号终止。

需要做的第一件事是在上下文需要保持活动的地方使用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。然而,就像这篇文章写的那样,可能已经改变了。