ZMQ Getting Started


前言

ZMQ(ØMQ、ZeroMQ, 0MQ)看起来像是一套嵌入式的网络链接库,但工作起来更像是一个并发式的框架。它提供的套接字可以在多种协议中传输消息,如线程间、进程间、TCP、广播等。你可以使用套接字构建多对多的连接模式,如扇出、发布-订阅、任务分发、请求-应答等。ZMQ的快速足以胜任集群应用产品。它的异步I/O机制让你能够构建多核应用程序,完成异步消息处理任务。ZMQ有着多语言支持,并能在几乎所有的操作系统上运行。ZMQ是iMatix公司的产品,以LGPL开源协议发布。

zmq本体是用C++实现的,提供C语言头文件。https://github.com/zeromq/libzmq
网站https://zeromq.org/get-started/的其它实现是对zmq接口的封装,需要依赖zmq库。


一、提问-回答 模式

client通过REQ socket发送Hello,server通过REP socket接收Hello并返回World
在这里插入图片描述
此例中,bind放在了server端,connect在client端,在zmq中其位置可以互换。server和client程序启动顺序无关,client先启动后会阻塞等待server启动。

  1. 一个进程只需要一个zmq context就可以了
  2. 一个zmq socket可多次bind
  3. zmq socket有严格的配对关系,只有特定类型的socket之间才可通讯 https://libzmq.readthedocs.io/en/latest/zmq_socket.html
  4. bind 和 connect是对等关系,位置可以互换
//  Hello World server
#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main (void)
{
    //  Socket to talk to clients
    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    int rc = zmq_bind (responder, "tcp://*:5555");
    assert (rc == 0);
    // 同一个socket可多次bind
    rc = zmq_bind(responder, "tcp://*:60000");
    assert(rc == 0);
    rc = zmq_bind(responder, "ipc://socket_type");
    assert(rc == 0);

    while (1) {
        char buffer [10];
        zmq_recv (responder, buffer, 10, 0);
        printf ("Received Hello\n");
        sleep (1);          //  Do some 'work'
        zmq_send (responder, "World", 5, 0);
    }
    zmq_close(responder);
    zmq_ctx_destroy(context);
    return 0;
}
//  Hello World client
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int main (void)
{
    printf ("Connecting to hello world server...\n");
    void *context = zmq_ctx_new ();
    void *requester = zmq_socket (context, ZMQ_REQ);
    zmq_connect (requester, "tcp://localhost:5555");

    int request_nbr;
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {
        char buffer [10];
        printf ("Sending Hello %d...\n", request_nbr);
        zmq_send (requester, "Hello", 5, 0);
        zmq_recv (requester, buffer, 10, 0);
        printf ("Received World %d\n", request_nbr);
    }
    zmq_close (requester);
    zmq_ctx_destroy (context);
    return 0;
}

client也可connect多次,具体内部实现不详

二、发布-订阅 模式

如下图,ZMQ 的 PUB-SUB是一对多的模式:
在这里插入图片描述

  1. bind一个发送方,多个接收方可接到相同的消息。即便没有sub,pub也一直再发。
  2. 可通过zmq_setsockopt设置多个filter,但如果不设置zmq_setsockopt则收不到任何数据。如果filter=“”,则接收所有数据
  3. ZMQ_SUB通过filter匹配接收信息的前缀
  4. ZMQ_PUB只能zmq_send; ZMQ_SUB只能zmq_recv
//  Weather update server
//  Binds PUB socket to tcp://*:5556
//  Publishes random weather updates
#include "zmq.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>

#define randof(num) (int)((float)(num)*random()/(RAND_MAX+1.0))

int main (void)
{
    //  Prepare our context and publisher
    void *context = zmq_ctx_new ();
    void *publisher = zmq_socket (context, ZMQ_PUB);
    int rc = zmq_bind (publisher, "tcp://*:5556");
    assert (rc == 0);

    //  Initialize random number generator
    srandom ((unsigned) time (NULL));
    while (1) {
        //  Get values that will fool the boss
        int zipcode, temperature, relhumidity;
        zipcode     = randof (100000);
        temperature = randof (215) - 80;
        relhumidity = randof (50) + 10;

        //  Send message to all subscribers
        char update [20];
        sprintf (update, "%05d %d %d", zipcode, temperature, relhumidity);
        zmq_send(publisher, update, sizeof(update), 0);
    }
    zmq_close (publisher);
    zmq_ctx_destroy (context);
    return 0;
}
//  Weather update client
//  Connects SUB socket to tcp://localhost:5556
//  Collects weather updates and finds avg temp in zipcode

#include "zmq.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
int main (int argc, char *argv [])
{
    //  Socket to talk to server
    printf ("Collecting updates from weather server...\n");
    void *context = zmq_ctx_new ();
    void *subscriber = zmq_socket (context, ZMQ_SUB);
    int rc = zmq_connect (subscriber, "tcp://localhost:5556");
    assert (rc == 0);

    //  Subscribe to zipcode, default is NYC, 10001
    const char *filter = (argc > 1)? argv [1]: "10001 ";
    rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,
                         filter, strlen (filter));
    assert (rc == 0);

    //  Process 100 updates
    int update_nbr;
    long total_temp = 0;
    char *string = (char*)malloc(BUFSIZ);
    for (update_nbr = 0; update_nbr < 100; update_nbr++) {
        int rx_size = zmq_recv(subscriber, string, BUFSIZ, 0);
        assert(rx_size >= 0);
        string[rx_size] = '\0';
        int zipcode, temperature, relhumidity;
        sscanf (string, "%d %d %d",
            &zipcode, &temperature, &relhumidity);
        total_temp += temperature;
    }
    printf ("Average temperature for zipcode '%s' was %dF\n",
        filter, (int) (total_temp / update_nbr));

    zmq_close (subscriber);
    zmq_ctx_destroy (context);
    return 0;
}

三、Divide and Conquer

  • ventilator产生可被并行处理的任务
  • 一系列的worker可以用于处理任务
  • sink收集worker的结果
    在这里插入图片描述
    现实中workers运行在超快的设备上,也许是在GPUs上解数学运算。

关于zmq context

  1. 一个进程只需有一个zmq context实例即可,如果有两个则会分离zmq实例。技术上说它是个容器。
  2. 如果使用fork,在子进程的开头调用一次zmq_ctx_new()。
  3. 使用zmq_send/recv可避免 直接使用zmq_msg_t 对象
  4. 使用zmq_msg_recv就需要zmq_msgclose
  5. zmq_ctx_new; zmq_socket; zmq_close; zmq_ctx_destroy;
  6. First, do not try to use the same socket from multiple threads. Please don’t explain why you think this would be excellent fun, just please don’t do it.

基础用法

利用zmq_msg_t,通过zmq_msg_recv接收并获取、处理数据,最后通过zmq_send发送

        zmq_msg_t message;
        zmq_msg_init(&message);
        int size = zmq_msg_recv(&message, response, 0);
        char* str = (char*)malloc(size + 100);
        memcpy(str, zmq_msg_data(&message), size);
        static int num = 0;
        snprintf(str+size, 100, " servid: %d, response: %d", pid, num++);
        zmq_send(response, str, strlen(str), 0);
        free(str);
        zmq_msg_close(&message);

ref

If you copy/paste a lot of code, you’re going to copy/paste errors, too.

https://github.com/zeromq/libzmq

ZGUIDE: https://zguide.zeromq.org/docs/chapter1/

https://wizardforcel.gitbooks.io/zmq-guide/content/chapter1.html

API: https://libzmq.readthedocs.io/en/latest/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值