ZeroMQ 套接字 Recv() 抛出“上下文已终止”异常 - 为啥以及如何恢复?
Posted
技术标签:
【中文标题】ZeroMQ 套接字 Recv() 抛出“上下文已终止”异常 - 为啥以及如何恢复?【英文标题】:ZeroMQ socket Recv() throws 'Context was terminated' exception - why and how to recover?ZeroMQ 套接字 Recv() 抛出“上下文已终止”异常 - 为什么以及如何恢复? 【发布时间】:2011-11-05 18:43:37 【问题描述】:使用带有 ZeroMQ 的ZMQ.SocketType.REP
(回复)消息套接字,我正在接收消息,然后发回“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);
【问题讨论】:
【参考方案1】:这意味着某人(垃圾收集器?)已经关闭了上下文。
【讨论】:
你是对的 - 上下文的设置方式是 GC 干扰它。谢谢!! 您能详细说明一下吗? 另一种方法是使用GC.KeepAlive
:msdn.microsoft.com/en-us/library/… 来防止对对象进行垃圾回收。【参考方案2】:
为了完整起见,添加此答案。
if (_zmqc == null)
_zmqc = new ZMQ.Context(1);
_recvSocket = _zmqc.Socket(ZMQ.SocketType.REP);
这是唯一使用上下文 _zmqc 的地方。因此,GC 将其视为清理的潜在候选对象。一旦它存在,就会调用它。这将强制所有套接字以来自 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。但是这只是 doco,因为这可能在编写后发生了变化。
【讨论】:
以上是关于ZeroMQ 套接字 Recv() 抛出“上下文已终止”异常 - 为啥以及如何恢复?的主要内容,如果未能解决你的问题,请参考以下文章
ZeroMQ 在套接字绑定到 ipc:// 协议地址(python)时抛出 ZMQError