简介

  • zmq通讯组件相关理论基础

概述

  • mq,是消息队列(message queue)的简称,目前有多种消息队列可用,包括RabbitMQ、Kafka等,它们各有特色,可以结合具体的项目需求使用。
  • ZeroMQ简称Zmq,或者0mq,核心引擎由c++编写,是轻量级消息通信库,在对传统的标准socket接口扩展的基础上形成的特色消息通信中间件。
  • Zmq提供了异步消息队列的抽象,具有多种消息通信模式,能够实现消息过滤,能够无缝对接多种传输协议。
  • 简言之,使用socket时,需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏 蔽了这些细节,让网络编程更简单
  • ZeroMQ是网络通信中新的一层,介于应用层和传输层之间(按照TCP/IP划分),是一个可伸缩层,可并行运行,分散在分布式系统间。
  • 官方描述
    • ZMQ(?MQ、ZeroMQ, 0MQ)看起来像是一套嵌入式的网络链接库,但工作起来更像是一个并发式的框架。它提供的套接字可以在多种协议中传输消息,如线程间、进程间、TCP、广播等。你可以使用套接字构建多对多的连接模式,如扇出、发布-订阅、任务分发、请求-应答等。ZMQ的快速足以胜任集群应用产品。它的异步I/O机制让你能够构建多核应用程序,完成异步消息处理任务。ZMQ有着多语言支持,并能在几乎所有的操作系统上运行。
  • ZMQ是iMatix公司的产品,以LGPLv3开源协议发布。

为什么要使用ZMQ

  • 当今的许多应用程序都包含了跨越某种网络的组件,无论这种网络是局域网还是互联网。因此,许多应用程序开发者最终都会处理某种类型的消息传递
  • 一些开发人员使用消息队列产品,但大多数时候,他们使用TCP或UDP自己做。
  • 这些协议并不难用,但是,​从 A 发送几个字节到 B 和以任何一种可靠的方式处理消息,这两者之间有很大的区别。

  • 让我们来看看当开始使用原始的TCP连接部件的时候,我们要面对的典型问题。任何可复用的消息层都需要解决如下所有这些问题或其中的大部分问题:
    • 我们如何处理I/O呢?
      • ​是让我们的应用程序阻塞,还是在后台处理I/O呢?这是一个关键的设计决策。阻塞式I/O 创建的架构不能很好地扩展,但后台I/O 也是非常难以正确做到的
    • 我们如何处理动态组件(例如,暂时撤除的块)呢?​
      • 我们需要正式将组件划分为“客户端”和“服务器”,并强制该服务器不能撤除吗?那么,如果我们想将服务器连接到服务器时该怎么办呢?我们需要每隔几秒钟就尝试重新连接吗?.
    • ​我们如何表示在线路上的消息呢?​
      • 我们应该怎样将数据组织为帧,才能使得它很容易写入和读取,避免缓冲区溢出,既对小型消息高效,也足以处理非常大的戴着聚会礼帽的跳舞猫的视频呢?
    • ​我们如何处理不能立即传递的消息呢?
      • ​特别是当我们在等待一个组件的联机回应时如何处理呢?我们需要丢弃消息,把它们放入一个数据库,或者把它们放到一个内存队列吗?
    • 我们在哪里存储消息队列呢?​
      • 如果组件从队列中读取很慢,导致我们的队列堆积,这会发生什么情况?我们的策略是什么呢?
    • 我们如何处理丢失的消息呢?
      • ​我们应该等待新的数据,要求重发,还是应该建立某种可靠性层,确保信息不会丢失呢?如果该层本身崩溃了该怎么办呢?
    • 如果我们需要使用一个不同的网络传输,比如说,用多播来取代TCP 单播,或IPv6,该怎么办呢?​我们需要重写应用程序吗?还是将传输抽象到某个层中呢?
    • 我们如何路由消息呢?​我们可以发送同样的消息到多个接收者吗?我们可以发送应答给原来的请求者吗?
    • 我们如何编写出另一种语言的API 呢?
      • ​我们应该重新实现一个线路级协议,还是重新包装一个库?如果是前者,我们怎么能保证协议栈的高效稳定呢?如果是后者,我们又怎么能保证互操作性呢?
    • ​我们应该如何表示数据,以便它可以在不同的架构之间读取呢?​我们应该对数据类型强制执行特定的编码吗?究竟到什么程度,才是消息传递系统的工作,而不是更高一层的工作呢?
    • ​我们应该如何处理网络错误呢?​是等待并重试,默默地忽略它们,还是终止它们呢?
  • ​ZeroMQ解决传统网络编程的问题:
    • 调用的socket接口较多。
    • TCP是一对一的连接。
    • 编程需要关注很多socket细节问题。
    • 不支持跨平台编程。
    • 需要自行处理分包、组包问题。
    • 流式传输时需处理粘包、半包问题。
    • 需自行处理网络异常,比如连接异常中断、重连等。
    • 服务端和客户端启动有先后。
    • 自行处理IO模型。
    • 自行实现消息的缓存。
    • 自行实现对消息的加密。

依赖环境

  • libzmq3-dev, libzmq5
  • libzmqpp-dev, libzmqpp4

客户端-服务器模式(Client-server)

  • 客户机-服务器模式用于允许一个ZMQ_SERVER服务器与一个或多个ZMQ_CLIENT客户机通信。客户端总是启动对话,之后任何一方都可以向另一方异步发送消息

ZMQ_CLIENT

  • ZMQ_CLIENT套接字与ZMQ_SERVER套接字通信。任何一个对等点都可以连接,但是通常推荐的模型是绑定ZMQ_SERVER并连接ZMQ_CLIENT。
  • 如果ZMQ_CLIENT套接字已经建立了连接,zmq_send()将接受消息,将它们排成队列,并在网络允许的情况下尽可能快地发送它们。传出缓冲区限制由套接字的高水位标志定义。如果传出缓冲区已满,或者没有连接的对等点,zmq_send()将默认阻塞。ZMQ_CLIENT套接字不会删除消息。
  • 当ZMQ_CLIENT套接字连接到多个ZMQ_SERVER套接字时,发送出去的消息将在连接的对等端之间循环分发。同样,ZMQ_CLIENT套接字公平地从每个连接的对等端接收消息。这种用法仅适用于无状态协议。
  • ZMQ_CLIENT套接字是线程安全的,可以从多个线程同时使用。注意,来自ZMQ_SERVER套接字的响应将发送到调用zmq_msg_recv()的第一个客户机线程。如果需要获得对原始线程的响应,每个线程使用一个ZMQ_CLIENT套接字。
  • ZMQ_CLIENT套接字是线程安全的。它们在发送时不接受ZMQ_SNDMORE选项,而在接收时不接受ZMQ_RCVMORE。这就限制了他们只能使用单个部件的数据。其目的是扩展API以允许分散/收集多部分数据。

  • ZMQ_CLIENT特性摘要 
    • 兼容的对等套接字ZMQ_SERVER方向双向的发送/接收模式无限制外发路由策略扇出(Fan out)入网路由策略公平排队静音状态下的操作阻塞

ZMQ_SERVER

  • ZMQ_SERVER套接字与一组ZMQ_CLIENT套接字通信。ZMQ_SERVER套接字只能应答传入消息:ZMQ_CLIENT对等端必须始终发起对话。
  • 每个接收到的消息都有一个routing_id,它是一个32位无符号整数。应用程序可以使用zmq_msg_routing_id(3)来获取它。要向给定的ZMQ_CLIENT对等点发送消息,应用程序必须使用zmq_msg_set_routing_id(3)在消息上设置对等点的routing_id。
  • 如果没有指定routing_id,或者没有引用已连接的客户端对等点,则发送调用将在EHOSTUNREACH中失败。如果客户端对等端的传出缓冲区已满,发送调用将阻塞,除非在发送中使用ZMQ_DONT_WAIT,在这种情况下,它将通过EAGAIN失败。ZMQ_SERVER套接字在任何情况下都不应该丢失消息。
  • ZMQ_SERVER套接字是线程安全的。它们在发送时不接受ZMQ_SNDMORE选项,而在接收时不接受ZMQ_RCVMORE。这就限制了他们只能使用单个部件的数据。其目的是扩展API以允许分散/收集多部分数据。

  • ZMQ_SERVER特性摘要 
    • 兼容的对等套接字ZMQ_CLIENT方向双向的发送/接收模式无限制外发路由策略扇出(Fan out)入网路由策略公平排队静音状态下的操作返回EAGAIN

其他

  • API参考文档:http://api.zeromq.org/master:_start