ZeroMQ 始终发送和获取 1 个字节(使用 cppzmq 绑定)

ZeroMQ always sends and gets 1 byte (using the cppzmq bindings)

以下服务器和客户端代码是 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 的用法。我读过这个“ 关于字符串的小注释" 重复:

ZeroMQ doesn't know anything about the data you send except its size in bytes. That means you are responsible for formatting it safely so that applications can read it back.

,后面跟着这句话:

So let's establish the rule that ZeroMQ strings are length-specified and are sent on the wire without a trailing null.

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

您似乎正在使用 returns bool 的功能。所以 true 转换为 1.

这解释了为什么您认为您收到并发送了 1 个字节。 我建议您改为在 message_t 对象上调用 size()

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 ();
    }

它 returns true 这就是为什么你的 length 等于 1.

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

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

感谢大家的帮助! 我认为调用重载 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;
}