转载自:http://www.codedump.info/?p=201
1) 全异步的处理
zeromq的几乎所有I/O操作,都是异步的,也就是说主线程不会被阻塞.如何完成这个工作?它会根据zmq_init函数中的参数创建对应数量的I/O thread,然后将I/O相关的操作push到这些I/O线程中.
每个I/O线程,都有一个与之绑定的poller(select,epoll等,根据平台不同选择使用不同的接口),然后主线程与绑定到I/O线程中的数据结构通过管道进行通信,主线程和I/O线程之间的消息处理函数封装在zmq::object_t::process_command函数中.通过消息,而不是线程间加解锁的方式进行编码,这也是erlang采用的编程范式,看上去理解起来也更加容易一些.
2) 例子
以这里举的echo service例子来说明整个流程.
我为这个例子专门画了一个.
我相信,如果没有读过zeromq源码的情况,阅读这份流程图还是会有一些困难的,不过我还是尽量说的清楚一些,以方便后来人.
a) I/O全部会分配到I/O线程中,就像前面提到的那样.在这个例子中,比如client端要发起对客户端的连接时,会创建一个zmq_connecter_t指针,并且将它绑定到I/O线程中,如何实现这个”绑定”,因为创建它的工作是在主线程中完成的,所以在选择好需要绑定的I/O线程之后,就通过发送消息的形式,将这个指针的地址放在消息中通过管道发送给I/O线程,这样就完成了绑定.其他类似的在主线程中创建的与I/O有关的数据,都是通过这种形式完成与指定I/O线程的绑定的.绑定完成之后,由于每个I/O线程都有一个poller,这样就可以把这个数据添加到poller中关注它的读/写情况了.
b) zmq_init_t指针.无论是客户端,还是服务器端,在进行连接时首先都要创建一个zmq_init_t指针,该指针用于相互间的第一次通信,客户端给服务器端发送自己的identity,如果没有特别指定,则是一个随机分配的字符串.也许这样是为了方便服务器端根据这个来查找区分不同的客户端吧.所以任何时候,连接完成时,接收到的第一条数据都是这些认证消息.
c) session_t指针.在完成上面的认证过程之后,双方将为这一次连接创建一个session_t指针,也就是任何一个session_t指针对应一次连接,同时此时会将完成任务的zmq_init_t指针删除.以后的通信,就完全依靠session_t指针了,session_t指针与主线程之间也是通过管道进行通信的.比如主线程调用zmq_send发送消息时,是通过管道将消息发送给对应的session,session再把消息发送给对端.接收消息的时候同样.