ZeroMQ之通信模式

官网地址  http://zeromq.org


1. API

int zmq_recv (void *socket, void *buf, size_t len, int flags);

int zmq_send (void *socket, void *buf, size_t len, int flags);

zmq_recv 和 zmq_send 默认都是阻塞的,可以通过flags=ZMQ_DONTWAIT参数来设置为非阻塞模式。  buf 和 len都是靠应用程序来保证的。

对于阻塞模式,zmq_recv的返回值是接收到的字节数,注意如果超过 len,后面的数据将会被截断,但返回值的长度却是原本没有被截掉的长度。 如果错误,或者在非阻塞模式下没有消息,返回-1,并设置  errno。


2. 模式

2.1 request - reply 模式

如果server重启,那么这个模式就会失效,也就是说 server 和 client就不通消息了(可以有办法来解决这个问题,还没有看到那部分),但如果client重启的话是没有关系的。


并且一定要遵循一问一答的顺序,比如 send --receive --send ---receive ,中间如果顺序错了,比如发了两次,或收了两次就会出错,返回-1,或者先收再发也会同样出错。所以这是一个完全同步的模式,因为zmq不像socket,没有socket这个概念,如果这不同步的话就不知道是哪个连接发过来的,比如A,B都合C相连,C在监听,那么当收到数据之后,如果先收两个包放在本地,然后一个个返回,那么这个时候他就不知道要给A还是B,因为没有任何对应关系可循,这都是封装在里面的。


2.2 publish - subscribe 模式

这个模式是单向的,就是说 pub只能发, sub只能收

sub可以注册多个pub,并且多个pub上的消息会公平的过来。

如果pub没有任何sub,那么消息将会被丢弃

如果sub消费得比较慢,消息就会堆积在pub端

在v3.x版本里面,tcp 或 ipc的过滤是发生在publisher,而在低版本里面,所有的过滤都是发生在subscriber,这样就比较浪费流量和资源


sub 除了要创建 ZMQ_SUB 类型的socket,并连接之外,还要 调用 zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,filter, strlen (filter)); 来进行注册,才有效果。 其中filter用来匹配消息开头的字符串,如果匹配则接受下来,否则丢弃;但如果filter = NULL,并且长度为0的话,则表示所有的消息都接收。 


publisher的第一个包经常是会被丢掉的,即便 sub端先起来,然后启动push 发送消息,刚开始的消息也有可能丢的  。因为即便是再快的网络,建立连接都是需要一些时间的,比如几个毫秒,而用zmq发送速度太快,在订阅者尚未与发布者建立联系时,已经开始了数据发布(内部局域网没这么夸张的),再结合之前说的如果publisher没有任何subscriber连上来的话消息会被丢弃。官网给了两个解决方案;1, 让发布者先不发数据,而是等订阅者真正连上之后,再发数据; 2,就是发布是永不停止的,没有开始与尽头的概念。


2.3  push-pull 模式

这个模式和publish-subscrible有点像,数据都是单向流动,但push-pull是基于负载均衡的任务分发,就是说如果有多个 pull端,那么push出去的数据将会平衡得分配到各个pull端,并且一旦有一个点拿到了数据,其他pull端就没有了,就是说所有的pull拿到的数据合起来才是push的数据总和。  而 publish - subscribe则是 publish的数据,所有的subscribe都可以收到,当然如果进行了过滤则只能收到符合规则的数据。


3. 其它


ZMQ的通信层,是不分哪个主动监听,哪个主动连接的,所以你可以在任意一端监听,另一端来connect。


context:一个进程只有一个context,所有的socket都在其中维护着,如果你创建了两个context,那么他们是完全独立的,一般不用这么做。 一般在开头创建context,在结尾 destory它。 如果先创建了context,然后fork了一个子进程,那么子进程会自动得到一个context,并且是和父进程独立的。 context是线程安全的,就是说多个线程可以共享它,并且不用加锁。


socket:不是线程安全的


3.2 资源清理

zmq对于资源的清理是很重要的,如果有一个socket没有关闭,那么zmq_ctx_destory 将会永远挂起,即便你关闭了socket,如果有pending的连接或发送的话,zmq_ctx_destory 照样会永远挂起,除非事先设置了LINGER。 

1)尽量使用zmq_send 和 zmq_recv 从而避免使用 zmq_msg_t;

2)如果你用了 zmq_msg_recv,那么尽快调用 zmq_msg_close去清理内存(不要直接操作成员变量啊)。

3) 如果你创建了很多socket又很快用完关闭,说明你的程序可能需要重新设计,有些时候socket的handle直到destory context的时候才会被释放。 

4)在程序的结束关闭socket,并destory context

5) 在zmq_ctx_detory的时候,如果有socket还在用那么会返回错误,捕捉这个错误,并设置LINGER,并关闭socket,contex会自动被销毁。注意不要zmq_ctx_detory一个context两次。


4. 多线程问题

不要在多个线程里面使用同一个socket,就是说socket只能在一个线程里面使用。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值