以下服务器和客户端代码是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发送的内容是什么?
答案 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
作为这些句子之间的分隔符。)