zoukankan      html  css  js  c++  java
  • ZeroMQ_11 请求应答---信封

    在请求-应答模式中,信封里保存了应答目标的位置。这就是为什么ØMQ网络虽然是无状态的,但仍能完成请求-应答的过程。

    在一般使用过程中,你并不需要知道请求-应答信封的工作原理。使用REQ、REP时,ØMQ会自动处理消息信封。下一章讲到的装置(device),使用时也只需保证读取和写入所有的信息即可。ØMQ使用多段消息的方式来存储信封,所以在复制消息时也会复制信封。

    然而,在使用高级请求-应答模式之前是需要了解信封这一机制的,以下是信封机制在ROUTER中的工作原理:

    • 从ROUTER中读取一条消息时,ØMQ会包上一层信封,上面注明了消息的来源。
    • 向ROUTER写入一条消息时(包含信封),ØMQ会将信封拆开,并将消息递送给相应的对象。

    如果将从ROUTER A中获取的消息(包含信封)写入ROUTER B(即将消息发送给一个DEALER,该DEALER连接到了ROUTER),那么在从ROUTER B中获取该消息时就会包含两层信封。

    信封机制的根本作用是让ROUTER知道如何将消息递送给正确的应答目标,你需要做的就是在程序中保留好该信封。回顾一下REP套接字,它会将收到消息的信封逐个拆开,将消息本身传送给应用程序。而在发送时,又会在消息外层包裹该信封,发送给ROUTER,从而传递给正确的应答目标。

    我们可以使用上述原理建立起一个ROUTER-DEALER装置:

    [REQ] <--> [REP]
    [REQ] <--> [ROUTER--DEALER] <--> [REP]
    [REQ] <--> [ROUTER--DEALER] <--> [ROUTER--DEALER] <--> [REP]
    ...etc.
    

    当你用REQ套接字去连接ROUTER套接字,并发送一条请求消息,你会从ROUTER中获得一条如下所示的消息:

    • 第三帧是应用程序发送给REQ套接字的消息;
    • 第二帧的空信息是REQ套接字在发送消息给ROUTER之前添加的;
    • 第一帧即信封,是由ROUTER套接字添加的,记录了消息的来源。

    如果我们在一条装置链路上传递该消息,最终会得到包含多层信封的消息。最新的信封会在消息的顶部。

    以下将详述我们在请求-应答模式中使用到的四种套接字类型:

    • DEALER是一种负载均衡,它会将消息分发给已连接的节点,并使用公平队列的机制处理接受到的消息。DEALER的作用就像是PUSH和PULL的结合。

    • REQ发送消息时会在消息顶部插入一个空帧,接受时会将空帧移去。其实REQ是建立在DEALER之上的,但REQ只有当消息发送并接受到回应后才能继续运行。

    • ROUTER在收到消息时会在顶部添加一个信封,标记消息来源。发送时会通过该信封决定哪个节点可以获取到该条消息。

    • REP在收到消息时会将第一个空帧之前的所有信息保存起来,将原始信息传送给应用程序。在发送消息时,REP会用刚才保存的信息包裹应答消息。REP其实是建立在ROUTER之上的,但和REQ一样,必须完成接受和发送这两个动作后才能继续。

    REP要求消息中的信封由一个空帧结束,所以如果你没有用REQ发送消息,则需要自己在消息中添加这个空帧。

    你肯定会问,ROUTER是怎么标识消息的来源的?答案当然是套接字的标识。我们之前讲过,一个套接字可能是瞬时的,它所连接的套接字(如ROUTER)则会给它生成一个标识,与之相关联。一个套接字也可以显式地给自己定义一个标识,这样其他套接字就可以直接使用了。

    这是一个瞬时的套接字,ROUTER会自动生成一个UUID来标识消息的来源。

    这是一个持久的套接字,标识由消息来源自己指定。

    下面让我们在实例中观察上述两种操作。下列程序会打印出ROUTER从两个REP套接字中获得的消息,其中一个没有指定标识,另一个指定了“Hello”作为标识。

    #include "../zhelpers.h"
    
    int main (void) 
    {
        void *context = zmq_ctx_new ();
        void *sink = zmq_socket (context, ZMQ_ROUTER);
        zmq_bind (sink, "inproc://example");
    
        //  First allow 0MQ to set the identity
        void *anonymous = zmq_socket (context, ZMQ_REQ);
        zmq_connect (anonymous, "inproc://example");
        s_send (anonymous, "ROUTER uses a generated 5 byte identity");
        s_dump (sink);
    
        //  Then set the identity ourselves
        void *identified = zmq_socket (context, ZMQ_REQ);
        zmq_setsockopt (identified, ZMQ_IDENTITY, "PEER2", 5);
        zmq_connect (identified, "inproc://example");
        s_send (identified, "ROUTER socket uses REQ's socket identity");
        s_dump (sink);
    
        zmq_close (sink);
        zmq_close (anonymous);
        zmq_close (identified);
        zmq_ctx_destroy (context);
        return 0;
    }

    out:

    ----------------------------------------
    [005] 006B8B4567
    [000] 
    [039] ROUTER uses a generated 5 byte identity
    ----------------------------------------
    [005] PEER2
    [000] 
    [040] ROUTER socket uses REQ's socket identity
  • 相关阅读:
    python自定义线程池
    sudo: ulimit: command not found
    HTTP长连接、短连接使用及测试
    5分钟上手:本地开发环境启动HTTPS
    Python复杂对象转JSON
    Python自定义注解
    gcc makefile
    Ubuntu 13.10 安装 ia32-lib
    vim扩展配置
    python异常类型
  • 原文地址:https://www.cnblogs.com/vczf/p/12935227.html
Copyright © 2011-2022 走看看