部分翻译自www.zeromq.org/whitepapers:architecture
概述
想要了解ZMQ内部结构的人越来越多,大量关于代码库的讨论经常提到的问题是缺乏一个可以让新人快速了解代码结构的架构文档。
本文的目的便是提供一种这样的文档。本文会逐步覆盖整个代码库,但是不会去关注太多的细节问题。因为随着时间的推移,细节部分可能与文档脱节。如果想要获得详细信息,你应该查看相关部分的源码。
首先需要提醒读者的是代码库是复杂的。从代码行数(也许是意大利面式的代码行数,我想ZMQ应该不是意大利面)的角度来看代码库并不复杂(目前有10000行)。想法,由于ZMQ要考虑大量不同的组合,因此是很复杂的。比如,它需要在超过10个操作系统的不同版本上运行;需要运行在许多不同的指令体系结构,从ARM到Itanium;可以由不同的编译器编译,从gcc,MSVC到SunStudio;可以与20多种不同语言绑定进行交互;可以使用不同的底层传输协议,不同的进程间消息传递机制并支持可靠多播;支持不同的消息模式:远程过程调用,数据分发,并行流水线等;每个socket可以连接或被连接到对等socket,或者同时建立双向连接;两个节点之间的通信失败可能是由于底层连接的中断也可能是暂时性的网络问题等等。所有这些选项是相互正交的,需要考虑到上千种可能的组合。
以上意思是说代码即使看起来很简单,很容易上手,但实际上很复杂。到目前为止,代码大约花费了10人年的工作量,每一行的代码上的花费大约是两个小时,包括像“i + +;”这样的代码。因此,在对代码做任何更改之前要小心仔细的了解代码在做什么和为什么要这样做。
全局状态
在库中使用全局变量绝对是一个搬起石头砸自己的脚的最佳方式。一切都工作良好除非库被链接到可执行文件两次(见图片),而这时你就会遇到古怪的错误和崩溃。为了防止这类问题, libzmq 没有使用全局变量,而是由使用者负责显式的创建全局状态。包含全局状态的对象被称为“上下文”(context)。从使用者的角度来看 context 或多或少像是供ZMQ socket使用的I/O线程池,在libzmq的观点来看context只是一个存储libzmq所需要的全局状态的对象。例如,进程内部使用的可用端点(endpoint)列表(已经关闭的但仍然逗留在内存中的ZMQ socket列表,之所以逗留在内存中是由于在上下文中有需要发出的消息)就存储在上下文中。
上下文由类 ctx_t 实现。