我已经用ZeroMQ创建了一个订阅者-订阅者通信方案,我注意到我的服务器和客户端程序有一个小问题。我知道在C中没有try catch(根据我的简短研究),但是在接下来的两个while(1)
中没有异常捕获对我来说似乎是危险的。
考虑到下面的代码片段,处理异常(在while中)的最正确方法是什么?使用我现在的结构(正如你在下面看到的),zmq_close
和zmq_ctx_destroy
将永远不会执行,但我希望它们在程序错误/异常(无论是什么原因)的情况下执行。
注意:在此架构中,我有一个客户端监听多个发布者,因此Client代码中的for
周期。
服务器
(...inside main)
while (1) {
char update[20];
sprintf(update, "%s", "new_update");
s_send(publisher, update);
sleep(1);
}
zmq_close(publisher);
zmq_ctx_destroy(context);
return 0;
客户端
(...inside main)
while(1){
for (c = 1; c < server_num; c = c + 1){
char *msg = s_recv(subscribers[c]);
if (msg) {
printf("%s\n",msg);
free(msg);
}
sleep(1);
}
}
for (c = 0; c < server_num; c = c + 1)
zmq_close(subscribers[c]);
zmq_ctx_destroy(context);
return 0;
3条答案
按热度按时间8qgya5xd1#
作为存在的标记error-handling:
Q:* 处理异常(while内部)的最正确方法是什么?*
最好的策略是***错误预防***,而不是*任何类型的“React性”(事后异常)处理。
总是假设事情可能会,并将成为破坏性的破坏,让他们失败便宜。失败的成本越低,系统就越好,也越快地恢复到它自己的预期行为。
也就是说,在现代低延迟分布式系统中,在实时系统中,异常是非常昂贵的,设计的代码执行流程的破坏性元素。
由于这些原因,以及为了保持最高性能的持续水平,ZeroMQ从此采用了一种非常不同的方法:
0)
在调用
zmq_recv()
的API函数之前,最好使用**zmq_poll()
作为任何可读消息(已经发送并准备好接收)存在(或不存在)的最便宜的检测**,以便从Context()
示例内部存储中将此类数据提取到应用程序级代码中。1)
根据你的语言绑定( Package 器),最好享受
.poll()
,.send()
和.recv()
方法的非阻塞形式。本机API是最直接的,始终使用**retCode = zmq_recv( ..., ZMQ_NOBLOCK );
**2)
始终分析 *
retCode
-无论是在沉默或解释assert( retCode == 0 && zmq_errno() )
或其他。3)
最好的审查和微调ZeroMQ框架中可用的示例化工具的所有配置属性,并利用其所有隐藏的优势来最好地满足您的应用程序域的需求。许多原生API设置可能有助于减轻(如果不是主要避免)
Context()
引擎示例中的大量冲突要求,因此不要犹豫,了解可能设置的所有细节,并尽可能地使用它们为您的代码提供帮助。如果不做以上所有这些,您的代码就不会 * 充分利用Zen-of-Zero
Q:* 在我现在的结构中(...),
zmq_close
和zmq_ctx_destroy
永远不会执行,但我希望它们能够执行,以防程序错误/异常(无论是哪个起源)。设置一个明确标志是足够公平的:
使用其他工具(如
int atexit(void (*func)(void));
)可以作为阿拉普调用zmq_close()
或zmq_ctx_term()
的最后手段3qpi33ja2#
你是对的,C没有try/catch的概念,但这不应该是一个问题。这只是意味着你需要在s_send()和s_recv()例程中处理异常(所以,例如,如果发生意外情况(如malloc()返回NULL),你必须处理它并继续处理或返回)。
我还建议您查看客户端的poll()或select()系统调用,而不是执行循环轮询。只为有数据等待读取的文件描述符提供服务要优雅得多。
fcipmucu3#
C中检查错误的惯用方法是查看返回值,然后检查errno是否为负。
您可能需要添加
#include <errno.h>
和<string.h>
,如果它不在您的程序中。您也可以阅读strerror文档。现在回答问题的这一部分:
考虑到下面的代码片段,处理异常(在while中)的最正确方法是什么?使用我现在的结构(正如你在下面看到的),zmq_close和zmq_ctx_destroy永远不会执行,但我希望它们在程序错误/异常的情况下执行(无论是什么原因)。
所有
zmq_*
函数将返回一个错误并设置errno。检查每个功能,并在发生错误时检查break
。在这种情况下,轮询非阻塞函数最好是在发生错误时将break
从while
循环中删除。在Linux上,您还可以设置一个信号处理程序,并在引发信号时执行一个清理例程(例如,在控制台中的cxpls +C上捕获SIGINT以正确退出UNIX上的程序是非常常见的)。看到这个答案了吗