繁体   English   中英

如何使用 ZeroMQ 开发简单的 DEALER/ROUTER 消息流?

[英]How could you develop a simple DEALER/ROUTER message flow, using ZeroMQ?

我对 TCP 消息传递(以及一般编程)相当陌生,我正在尝试使用 ZeroMQ 开发一个简单的 ROUTER/DEALER 消息对,但在让路由器接收来自经销商的消息并发送回消息方面遇到了困难。

我可以毫无问题地做一个简单的REQ/REP模式,我可以将一条消息从我的机器发送到我的虚拟机。

但是,当尝试开发ROUTER/DEALER对时,我似乎无法让ROUTER -instance 接收消息(VM 上的ROUTER ,主机上的DEALER )。 我已经取得了一些成功,我可以在while(){...}循环中发送 50 条消息,但不能发送一条消息并让ROUTER发回一条消息。

所以从我所读到的, ROUTER/DEALER对中的 TCP 消息以开头的分隔符 0 发送,并且必须首先将这个 0 发送到ROUTER以注册传入的消息。

所以我只想将消息"ROUTER_TEST"发送到我的服务器,并让我的服务器以"RECEIVED"响应。

经销商

#include <cstdlib>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

#include "zmq.h"

const char connection[] = "tcp://10.0.10.76:5555";
int main(void)
{
    int major, minor, patch;
    zmq_version(&major, &minor, &patch);
    printf("\nInstalled ZeroMQ version: %d.%d.%d\n", major, minor, patch);
    printf("Connecting to: %s\n", connection);

    void *context = zmq_ctx_new();

    void *requester = zmq_socket(context, ZMQ_DEALER);

    int zc = zmq_connect(requester, connection); 
    std::cout << "zmq_connect = " << zc << std::endl;

    int sm = zmq_socket_monitor(requester, connection, ZMQ_EVENT_ALL);
    std::cout << "zmq_socket_monitor = " << sm << std::endl;

    char messageSend[] = "ROUTER_TEST";

    int request_nbr;
    int n = zmq_send(requester, NULL, 0, ZMQ_DONTWAIT|ZMQ_SNDMORE );
    int ii = 0;
    if(n==0) {
        std::cout << "n = " << n << std::endl;
    while (ii < 50)
    {
        n = zmq_send(requester, messageSend, 31, ZMQ_DONTWAIT);

        ii++;
    }
    }

    return 0;
}

路由器

// SERVER
#include <cstdlib>
#include <iostream>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

#include "zmq.h"

int main(void)
{
    void *context = zmq_ctx_new();
    void *responder = zmq_socket(context, ZMQ_ROUTER);
    printf("THIS IS WORKING - ROUTER\n");
    int rc = zmq_bind(responder, "tcp://*:5555");
    assert(rc == 0);

    zmq_pollitem_t pollItems[] = {
        {responder, 0, ZMQ_POLLIN, -1}};

    int sm = zmq_socket_monitor(responder, "tcp://*:5555", ZMQ_EVENT_LISTENING);
    std::cout << "zmq_socket_monitor = " << sm << std::endl;
    uint8_t buffer[15];
    while (1)
    {
        int rc = zmq_recv(responder, buffer, 5, ZMQ_DONTWAIT);
        if (rc == 0)
        {
            std::cout << "zmq_recv = " << rc << std::endl;
            zmq_send(responder, "RECIEVED", 9,0);
        }

        zmq_poll(pollItems, sizeof(pollItems), -1);

    }
    return 0;
}

您的代码在DEALER端调用了一系列:

void *requester = zmq_socket( context,
                              ZMQ_DEALER           // <--   .STO <ZMQ_DEALER>, *requester
                              );
...
int n   = zmq_send( requester, // <~~ <~~ <~~ <~~ <~~ <~~   .STO 0, n
                    NULL,     //                             NULL,sizeof(NULL)== 0
                    0,       //                              explicitly declared 0
                    ZMQ_DONTWAIT                   //           _DONTWAIT flag
                  | ZMQ_SNDMORE                    //---- 1x ZMQ_SNDMORE  flag== 
                    );                             //        1.Frame in 1st MSG
int ii  = 0;                                       //        MSG-under-CONSTRUCTION
if ( n == 0 )                                      //     ...until complete, not yet sent
{    
     std::cout << "PREVIOUS[" << ii << ".] CALL of zmq_send() has returned n = " << n << std::endl;
     
     while ( ii < 50 )
     {       ii++;
             n = zmq_send( requester,   //---------//---- 1x ZMQ_SNDMORE following
                           messageSend, //         //        2.Frame in 1st MSG
                           31,          //         //        MSG-under-CONSTRUCTION, but
                           ZMQ_DONTWAIT //         //        NOW complete & will get sent
                           );           //---------//----49x monoFrame MSGs follow
     }
}
...

对面的ROUTER端代码会发生什么?

...
while (1)
{       
        int  rc  = zmq_recv( responder, //----------------- 1st .recv()
                             buffer,
                             5,
                             ZMQ_DONTWAIT
                             );
        if ( rc == 0 )
        {
            std::cout << "zmq_recv = " << rc << std::endl;
            zmq_send( responder,  // _____________________ void  *socket
                      "RECEIVED", // _____________________ void  *buffer
                      9,  // _____________________________ size_t len
                      0   // _____________________________ int    flags
                      );
        }
        zmq_poll( pollItems,
                  sizeof( pollItems ),
                  -1 // __________________________________ block ( forever )
                  );//                                     till  ( if ever ) ...?
}

在这里,最有可能的是rc == 0但一次,如果没有错过,但永远不会更多

请注意,如果.recv()也被ZMQ_RECVMORE标记,则您的代码不会以任何方式检测到 - 表示需要首先还.recv() -all-the-rest multi-Frame 部分第一条消息,在能够.send() -any-answer 之前...

处理多部分消息的应用程序必须在调用zmq_recv()后使用ZMQ_RCVMORE zmq_getsockopt(3)选项来确定是否还有要接收的部分。

接下来, buffermessageSend消息-“有效负载”是一种脆弱的实体,应该重新组合(有关详细信息,最好再次阅读有关如何仔细初始化、使用和安全触摸任何zmq_msg_t对象的所有详细信息) ,在成功.send()/.recv()之后,低级 API (自 2.11.x+ 起)认为它们已被丢弃,不可重复使用。 另请注意, messageSend不是(如强制放入代码中的那样) 31- char[] ,是吗? 有没有特别的意图这样做?

如果成功, zmq_send() function 将返回消息中的字节数。 否则它将返回-1并将errno为下面定义的值之一。 { EAGAIN, ENOTSUP, EINVAL, EFSM, ETERM, ENOTSOCK, EINTR, EHOSTUNREACH }

不测试错误状态意味着对REQ/REPDEALER/ROUTER (扩展) EFSM .send()/.recv()/.send()/.recv()/...这些步骤的强制性 dFSA 顺序


“所以从我读到的内容来看, ROUTER/DEALER对中的 TCP 消息以开头的分隔符 0 发送,并且必须首先将这个 0 发送到ROUTER以注册传入消息。”

这似乎是一个被误解的部分。 应用程序端可以自由编写任意数量的单帧或多帧消息,但是在没有用户帮助的情况下执行ROUTER前置身份帧的“技巧”(消息标记是在任何之前自动执行的(现在,主要是所有) multi-frame(d) 消息被传递到应用程序端(使用接收方的.recv() -method )。上面提到了对多帧消息的适当处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM