- ZeroMQ应用程序总是从创建一个上下文开始,然后使用它来创建套接字。
- 上下文是指:在单个进程中所有套接字的容器,并充当inproc套接字的传输工具,这是在一个进程中连接线程的最快办法。
- 单个进程中可以有多个上下文,不会出错,它们彼此之间都是独立的ZeroMQ实例,因此你需要自己做好处理。
- 但是一般使用规则为:在你的主代码开始处执行一个zmq_ctx_new()、在代码最后执行一个zmq_ctx_destroy()。
-
父子进程之间的上下文:
- 父子进程之间一般都要拥有自己的上下文。
- 如果父进程调用zmq_ctx_new()创建了上下文,fork()之后子进程会获得自己的上下文。
zmq_ctx_new()
void *zmq_ctx_new ();
- API参考手册:http://api.zeromq.org/master:zmq-ctx-new。
- 功能:该函数创建一个新ØMQ上下文。
- 该函数替换了已过时的zmq_init()函数。
- 返回值:
- 如果成功,函数向新创建的上下文返回不透明句柄。
- 否则,它将返回NULL。
- errno:没有为此函数定义错误值。
- 线程安全:ØMQ上下文是线程安全的,可以根据需要在任意多个应用程序线程之间共享,而调用方无需进行任何其他锁定。
二、执行彻底的退出zmq_ctx_term()
int zmq_ctx_term(void *context);
- API参考手册:http://api.zeromq.org/master:zmq-ctx-term。
- 功能:该函数终止一个ØMQ上下文。
- 参数:上下文句柄(配对的zmq_ctx_new()函数的返回值)。
- 返回值:
- 如果成功,函数返回零。
- 否则,它将返回-1并将errno设置为以下定义的值之一:
- EFAULT:提供的上下文无效。
- EINTR:终止被信号中断。如果需要,可以重新启动它。
- 上下文终止按以下步骤执行:
- 当前在上下文中打开的套接字上正在进行的任何阻塞操作都应立即返回,并返回错误代码ETERM。除zmq_close()之外,在上下文中打开的套接字上的任何进一步操作均将失败,并显示错误代码ETERM。
- 在中断所有阻塞调用之后,zmq_ctx_term()将阻塞直到满足以下条件:
- 在上下文中打开的所有套接字都已使用zmq_close()关闭。
- 对于上下文中的每个套接字,应用程序使用zmq_send()发送的所有消息都已物理传输到网络对等方,或者使用套接字ZMQ_LINGER选项设置的套接字停留时间已到期。
- 附加:
- 有关套接字延迟行为的更多详细信息,请参考zmq_setsockopt()中的ZMQ_LINGER选项。
- 该函数替换了不推荐使用的zmq_term()和zmq_ctx_destroy()函数。
-
让程序的彻底退出一般有两个原因:
- ①对于C/C++程序来说,在程序终止之后一般需要对申请的资源进行释放,否则就会造成泄漏。
- ②如果任何套接字保持打开,那么zmq_ctx_term()函数将一直挂起;如果套接字已经全部关闭,但是有悬而未决的连接或发送,那么zmq_ctx_term()默认也将等待下去。除非你在关闭这些套接字之前,将它们的LINGER(延期)设置为0。
建议如下
- 一个ZeroMQ对象包括消息、套接字、上下文。
- 所以,在简单的程序中,一般建议的规则为:
- 处理完消息的那一刻,总是调用zmq_msg_close()关闭它。
- 如果你打开和关闭了很多套接字,那么你的程序可能设计的不太合理,可以考虑重新设计程序。
- 当你退出程序时,关闭你的套接字,然后调用zmq_ctx_term()销毁上下文。
- 至少C语言是这样的。在自动销毁对象的语言中,当你离开作用域时,套接字和上下文将销毁。
- 如果你使用异常,必须在一个类似“final”块的东西中执行清理工作。
三、设置上下文选项(zmq_ctx_set)多线程中的处理
- 如果是多线程,那么情况可能会复杂一些,在后面的章节中我们会研究多线程,此处只是简单地一些介绍。
- 一般的规则为:
- 首先,不要在多个线程中使用同一个套接字。
- 接着,你需要关闭每个有持续请求的套接字,正确的方法是先设置一个低的LINGER值(1秒),然后关闭套接字。
- 最后销毁上下文,这将导致任何连接到线程(即,它们共享相同的上下文)的阻塞的接收或调查或发送都返回一个错误。捕获该错误,然后在该线程中设置LINGER,关闭套接字并退出。
- 不要多次销毁同样的上下文。
- 在主线程中的zmq_ctx_term()调用将会保持阻塞,直到它直到的所有套接字都已安全地关闭为止。
int zmq_ctx_se(void *context, int option_name, int option_value);
- API参考手册:http://api.zeromq.org/master:zmq-ctx-set。
- 功能:设置上下文。
-
参数:
- context:上下文指针。
- option_name:设置的上下文选项,见下面的表格。
- option_value:对应参数2的设置值。
选项值 | 含义 |
ZMQ_BLOCKY(修复阻止行为) |
|
ZMQ_IO_THREADS(设置I / O线程数) |
|
ZMQ_THREAD_SCHED_POLICY(设置I / O线程的调度策略) |
|
ZMQ_THREAD_PRIORITY(设置I / O线程的调度优先级) |
|
ZMQ_THREAD_AFFINITY_CPU_ADD(将CPU添加到I / O线程的相似性列表) |
|
ZMQ_THREAD_AFFINITY_CPU_REMOVE(从CPU移除对I / O线程的相似性列表) |
|
ZMQ_THREAD_NAME_PREFIX(设置I / O线程的名称前缀) |
|
ZMQ_MAX_MSGSZ(设置最大邮件大小) |
|
ZMQ_ZERO_COPY_RCV(指定消息解码策略) |
|
ZMQ_MAX_SOCKETS(设置最大套接字数) |
|
ZMQ_IPV6(设置IPv6选项) |
|
-
返回值:
- 成功:
- 失败:返回-1,并将errno设置为以下定义值之一:
- EINVAL:请求的选项option_name未知。
- 演示案例:设置套接字数量限制。
void *context = zmq_ctx_new ();
zmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);
int max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);
assert (max_sockets == 256);
四、获取上下文选项(zmq_ctx_get())I/O线程(ZMQ_IO_THREADS选项)
- 默认情况下,ØMQ在1个后台线程中执行I/O。当你创建一个新的上下文时,后台的I/O线程开始工作。
- 除最极端的应用程序外,1个I/O线程(用于所有套接字)足以供所有应用程序使用。
- 如果想要提高I/O线程的数量,可在创建任何套接字前使用zmq_ctx_set()函数设置I/O线程的数量。例如:ZMQ_IO_THREADS选项指定的大小ØMQ线程池来处理I/O操作。此选项仅适用于在上下文上创建任何套接字之前。
int io_threads = 4; void *context = zmq_ctx_new(); //设置I/O线程数量 zmq_ctx_set(context, ZMQ_IO_THREADS, io_threads); assert(zmq_ctx_get(context, ZMQ_IO_THREADS) == io_threads);
- 如果应用程序仅使用inproc来进行线程间通信(即一个不执行外部套接字I/O的多线程的应用程序),则可以把I/O线程数设置为0。
int zmq_ctx_get(void *context, int option_name);
- API参考手册:http://api.zeromq.org/master:zmq-ctx-get。
- 功能:获取上下文选项。
-
参数:
- context:上下文指针。
- option_name:相关选项,如下所示。
选项值 | 含义 |
ZMQ_IO_THREADS(获取I/O线程数) | 返回当前上下文背景下的线程池的大小 |
ZMQ_MAX_SOCKETS(获取最大套接字数) | 返回当前上下文背景下的套接字的最大数量 |
ZMQ_MAX_MSGSZ(获取最大消息大小) | 返回当前上下文背景下的消息的最大大小。默认值为INT_MAX |
ZMQ_ZERO_COPY_RCV(获取消息解码策略) | 接收消息时返回参数是否消息解码器使用一个零复制策略。默认值为1。(备注:此选项在DRAFT状态下,尚不能在稳定版本中使用) |
ZMQ_SOCKET_LIMIT(获取最大数量的可配置套接字) | 返回可设置的socket套接字的最大值 |
ZMQ_IPV6(获取IPv6选项) | 返回上下文中IPv6选项 |
ZMQ_BLOCKY(获取阻塞设置) |
|
ZMQ_THREAD_SCHED_POLICY(获取I/O线程的调度策略) | 返回上下文的线程池调度策略 |
ZMQ_THREAD_NAME_PREFIX(获取I/O线程的名称前缀) | 获取为内部上下文的线程池创建的每个线程的数字前缀 |
ZMQ_MSG_T_SIZE(在运行时获取zmq_msg_t的大小) | 返回zmq_msg_t结构在运行时的大小,这是在include/zmq.h公共头中定义的。这对于不能简单地执行sizeof()的FFI绑定很有用 |
-
返回值:
- 成功:返回0或更大的值。
- 否则,返回-1,并将errno设置为以下定义值之一:
- EINVAL:请求的选项option_name未知。
- 演示案例:设置套接字数量限制并获取:
void *context = zmq_ctx_new ();
zmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);
int max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);
assert (max_sockets == 256);
- 演示案例:关闭上下文死锁技巧:
zmq_ctx_set (ctx, ZMQ_BLOCKY, false);
五、关闭上下文(zmq_ctx_shutdown())
int zmq_ctx_shutdown(void *context);
- API参考手册:http://api.zeromq.org/master:zmq-ctx-shutdown。
- 功能:关闭上下文。
- 上下文关闭将导致在上下文中打开的套接字上当前正在进行的任何阻塞操作立即返回,错误代码为ETERM。除zmq_close()之外,在上下文中打开的套接字上的任何进一步操作均将失败,并显示错误代码ETERM。
- 与zmq_ctx_term()函数关系:zmq_ctx_shutdown()函数的使用是可选的,其只关闭上下文但是不释放上下文相关的资源。因此在调用该函数之后一般还需要调用zmq_ctx_term()来释放ZeroMQ所分配的资源该。
- 参数:要关闭的上下文。
-
返回值:
- 成功:返回0。
- 失败:返回-1并将errno设置为如下值之一:
- EFAULT:提供的上下文无效。
- zmq_init():初始化一个上下文,已被zmq_ctx_init()替代,API参考手册:http://api.zeromq.org/master:zmq-init。
- zmq_term():销毁上下文,已被zmq_ctx_term()替代,API参考手册:http://api.zeromq.org/master:zmq-ctx-term。
- zmq_ctx_destroy():销毁上下文,已被zmq_ctx_term()替代,API参考手册:http://api.zeromq.org/master:zmq-ctx-destroy。
- 我是小董,V公众点击"笔记白嫖"解锁更多【ZeroMQ】资料内容。