ZeroMQ总是发送并获取1个字节(使用cppzmq绑定)

时间:2016-12-09 17:11:08

标签: c++ zeromq

以下服务器和客户端代码是the official tutorial的略微修改版本。我对它们的输出的解释是它们发送或接收的任何内容总是1个字节。怎么会发生这种情况?

server.cpp:

#include <zmq.hpp>
#include <string>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
#define sleep(n) Sleep(n)
#endif

int main () {
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:5555");
    while(true){
        zmq::message_t request;
        int length=socket.recv(&request);
        if(length >= 0)
            std::cout << length << " bytes received:" << std::string((char*)request.data(),length) << ":" << std::endl;
        sleep(1);
        zmq::message_t reply(5);
        memcpy(reply.data(), "World", 5);
        socket.send(reply);
    }
    return 0;
}

服务器输出:

1 bytes received:H:

client.cpp:

#include <zmq.hpp>
#include <string>
#include <iostream>
int main ()
{
    zmq::context_t context(1);
    zmq::socket_t socket(context,ZMQ_REQ);
    socket.connect ("tcp://localhost:5555");
    zmq::message_t request(5);
    memcpy(request.data(),"Hello",5);
    std::cout << socket.send(request) << " bytes sent." << std::endl;
    zmq::message_t reply;
    int length=socket.recv(&reply);
    if(length >= 0)
        std::cout << length << " bytes received:" << std::string((char*)request.data(),length) << ":" << std::endl;
    return 0;
}

客户输出:

1 bytes sent.
1 bytes received:H:

鉴于这种奇怪的结果,我开始怀疑我可能会误解ZeroMQ的用法。我已经读过这个&#34; Minor Note on Strings&#34;反复:

  

除了大小(以字节为单位)外,ZeroMQ对您发送的数据一无所知。这意味着您有责任安全地格式化它,以便应用程序可以读回来。

,后跟这句话:

  

因此,让我们建立一个规则,即ZeroMQ字符串是长度指定的,并且在线路上发送而没有尾随空值。

这两段对我来说是矛盾的。确切了ZeroMQ发送的内容是什么?

3 个答案:

答案 0 :(得分:2)

您似乎正在使用返回bool的函数。因此true会转换为1

这解释了为什么你相信你收到并发送了1个字节。 我建议您在size()对象上致电message_t

答案 1 :(得分:2)

感谢所有的帮助! 我认为调用重载size_t send (const void *buf_, size_t len_, int flags_ = 0)而不是bool send (message_t &msg_, int flags_ = 0)会使代码比C更多C ++。这是不处理异常的工作版本:

server.cpp:

//  Hello World server in C++
//  Binds REP socket to tcp://*:5555
//  Expects "Hello" from client, replies with "World"
//
#include <zmq.hpp>
#include <string>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
#define sleep(n) Sleep(n)
#endif

int main () {
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:5555");
    while(true){
        zmq::message_t request;
        if(socket.recv(&request))
            std::cout << request.size() << " bytes received:" << std::string((char*)request.data(),request.size()) << std::endl;
        sleep(1);
        std::cout << socket.send("world",5,0) << " bytes replied" << std::endl;
    }
    return 0;
}

client.cpp:

//  Hello World client in C++
//  Connects REQ socket to tcp://localhost:5555
//  Sends "Hello" to server, expects "World" back
//
#include <zmq.hpp>
#include <string>
#include <iostream>

int main ()
{
    zmq::context_t context(1);
    zmq::socket_t socket(context,ZMQ_REQ);
    socket.connect ("tcp://localhost:5555");
    std::cout << socket.send("Hello",5,0) << " bytes sent." << std::endl;
    zmq::message_t reply;
    if(socket.recv(&reply))
        std::cout << reply.size() << " bytes received:" << std::string((char*)reply.data(),reply.size()) << std::endl;
    return 0;
}

答案 2 :(得分:1)

ZMQ可以发送和接收原始字节。建议使用zmq::message_t,因为它会为您处理许多边缘情况,并且通常很好用。

查看recv in zmq.hpp (link)的实施:

    inline bool recv (message_t *msg_, int flags_ = 0)
    {
        int nbytes = zmq_msg_recv (&(msg_->msg), ptr, flags_);
        if (nbytes >= 0)
            return true;
        if (zmq_errno () == EAGAIN)
            return false;
        throw error_t ();
    }

返回true,这就是您的length等于1的原因。

你引用的段落并不矛盾。它表示你永远不应该假设你收到的数据是NULL终止的,这意味着你不应该调用printf("%s", request.data()),因为printf可能会尝试访问未分配的内存。但是,您可以改用printf("%.*s", (int)request.size(), request.data())

毕竟,ZMQ发送你告诉它发送的字节,所以基本上你可以发送任何东西然后接收消息并解压缩它以理解它(例如当你在一个zmq::message_t中发送多个句子时你使用\0作为这些句子之间的分隔符。)