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



以下服务器和客户端代码是官方教程的略微修改版本。我对它们的输出的解释是,无论它们发送或接收什么,总是 1 个字节。怎么会这样?

服务器.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:

客户端.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除了以字节为单位的大小外,对您发送的数据一无所知。这意味着您负责安全地格式化它,以便应用程序可以读回它。

,后面跟着这句话:

因此,让我们建立规则,即 ZeroMQ 字符串是长度指定的,并且在没有尾随 null 的情况下通过网络发送。

这两段对我来说是矛盾的。确切地说,ZeroMQ发送了哪些内容?

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

服务器.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;
}

客户端.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;
}

您似乎正在使用返回bool的函数。所以true转换为1.

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

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

查看zmq.hpprecv的实现(链接):

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.

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

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

最新更新