zeromq笔记

http://blog.163.com/aslan_xin/blog/static/168196443201122801432555/

zeromq的特点
1.将所有io处理由一些io线程完成。
2.线程间通过传送对象指针,将本该由应用线程完成的io操作,交给io线程完成。
几种模式
PUB and SUB
类似于观察模式,一旦有消息要发送,PUB会发送所有SUB。如果PUB发送消息时,SUB还没有启动,那么SUB会漏掉该消息。
PUSH and PULL
一个1-to-n队列的实现,PUSH将数据放入队列,PULL从队列中不取出数据。当PUSH或PULL都可以作为服务端,面向n个PULL或PUSH。当PUSH作为服务端时,数据会负载均衡的发送给某一个PULL。
PAIR
线程间1-to-1队列的实现,采用了lock free实现,所以速度很快。
REQ 、REP、XREQ、XREP
REQ 发送完消息后,必须接收一个回应消息后,才能发送新的消息。REP当接收消息时,都会返回一个消息。XREQ和XREP是REQ和REP的扩展版,它们 1-to-N个连接,没有REQ和REP的限制。XREQ 发送消息时,负载平衡的发给所有的连接。XREP发送消息时,需要应用程序提供一个identity,消息只发送给该identity对应的链接。
通信方式
zeromq的通信方式有两种:command_t和pipe_t方式。
1 command_t将其它io对象的io操作交给io线程处理,主要有:
plug命令:将一个io对象注册到一个io线程
own命令:将两个对象绑定,
attach命令:绑定engine和session
bind命令:session和socket绑定
2 pipe_t方式实现了一个lock free 的管道,用于线程间的大量数据的传输,如io线程接收完数据后将数据传输给应用线程,pair模式也是直接采用pipe_t实现通信。
主要处理流程
感觉zeromq的特点是:将所有io处理由多个io线程单独完成,io线程与应用线程独立。每一个io操作的对象都与一个io线程绑定,它的所有io操作都有该io线程完成。线程间通过一种command_t格式,通过传送命令类型和对象指针,将本该由应用线程调用的函数,交给io线程完成。app线程发送和接收时通过队列和io线程交换数据。

1. zmq初始化(zmq_init())。
       主要实现在ctx_t::ctx_t()中。ctx_t维护了一个应用线程池,一个io线程池,和一个signaler池。ctx_t()中初始化了 signalers池,io线程(io_thread_t)池。每个io线程和app线程都有一个signaler,signaler处理线程间的 command_t,在unix中的实现是本地套接字。io_thread_t在构造时,使用select,poll, kqueue,epoll中的一种方式监听io,将io_thread_t线程的signaler也添加到监听事件。之后 io_thread_t->start(),开启多线程。如果采用kqueue, 则最终会调用kqueue_t::loop(),kqueue_t::loop()是个while循环,当有监听事件发生时,交给对应的hook进行处 理。对于io_thread_t线程的signaler,如果有读事件发生,则交由io_thread_t::in_event()处理。
 
2. 创建socket(zmq_socket())。
       主要实现在ctx_t::create_socket()中。创建app线程(app_thread_t),与一个signaler进行绑定。调用 app_thread_t::create_socket, 确定app线程该应用采用哪种连接模式。ZMQ_PAIR、ZMQ_PUB、 ZMQ_SUB、ZMQ_REQ、ZMQ_REP、ZMQ_XREQ、ZMQ_XREP、ZMQ_PULL、ZMQ_PUSH分别对应pair_t、 pub_t、sub_t、req_t、rep_t、xreq_t、xrep_t、pull_t、push_t。它们继承自socket_base_t,实 现了xsend(),xrecv()等接口。
 
3 监听连接(zmq_bind())
       以tcp为例,socket_base_t::bind()中创建一个zmq_listener_t对象,调用 zmq_listener_t::set_address()完成socket(),bind(),listen()系统调用。调用 send_plug(),向负载最低的io线程发送对象指针zmq_listener_t。io线程接到该命令后,调用 zmq_listener_t::process_plug()来处理,从而由io_thread监听该fd。该fd上收到连接请求时,交由 zmq_listener_t::in_event()处理。
 
4 服务端建立连接
       当有新的连接时,zmq_listener_t::in_event()调用tcp_listener::accept()完成accept()操作,获 取新连接的fd。创建一个 zmq_init_t对象,向负载最低io线程发送对象指针zmq_init_t*,io线程接到该命令后,完成以下调用 zmq_init_t::process_plug()->zmq_engine::plug(),io线程开始监听新的fd。
       当收到读事件时,由zmq_engine_t::in_event()处理,调用tcp_socket_t::read()完成 recv()系统调用,decoder_t::process_buffer()对读到的数据进行解码,解码完成后会调用 zmq_init_t::write(), 读到的第一个数据只可能是一个客户端的标示,以后就通过该标示来区分不同的客户端。zmq_init_t主要进行连接的初始化工作,开始接收数据后,它的 使命也就结束了,zmq_engine_t::in_event() ->zmq_init_t::flush() ->zmq_init_t::finalise () 中,调用engine->unplug () 断开zmq_engine_t和zmq_init_t的关联, 调用send_attach()发送attach命令,对象指针为session_t*, io线程收到命令后调用session_t::process_attach()。
       process_attach()中调用send_bind()将session_t和socket_base_t想关 联,engine->plug()将zmq_engine_t和session_t相关联,之后,有新的数 据时,decoder_t::process_buffer()处理完成后向队列中写数据,app线程不断的从队列的另一端读数据。
 
5 客户端建立连接(zmq_connect())
       以tcp为例,socket_base_t::connect()中,创建session_t(用于app线程与io线程发送与接收时数据的传送),构造 zmq_connecter_t,调用zmq_connecter_t::set_address()设置连接地址。向io线程发送对象指针 zmq_connecter_t,完成以下调用 zmq_connecter_t::process_plug()->zmq_connecter_t::start_connecting()->tcp_connecter_t::open () ,tcp_connecter_t::open () 中会完成socket (),connect()操作,io线程开始监听新的fd。

6 数据的接收(zmq_recv())
    连接建立起来后,收到读事件则由zmq_engine::in_event()处理。调用tcp_socket_t::read()完成 recv()系统调用。然后调用zmq_init::flush->zmq_init_t::finalise () ,创建一个session_t,调用send_attach()发送attach命令。io线程收到命令后调用session_t::process_attach(), process_attach()中创建pipe_t(pipe_t的实现是一个队列),调用send_bind()发送bind命令。io线程收到命令后调用session_t::process_attach(),将创建的pipe_t与对应的app线程对应的连接模式进行关联,之后app线程的接收数据都从pipe_t中获取。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值