Reputation: 769
The following server and client codes are slightly modified versions of the official tutorial. My interpretation of their outputs is that whatever they send or receive are always 1 byte. How can this happen?
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;
}
server ouput:
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;
}
client output:
1 bytes sent.
1 bytes received:H:
Given such strange results, I start to suspect that I might misunderstand ZeroMQ's usage. I have read this " Minor Note on Strings" repeatedly:
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.
, which is followed by this sentence:
So let's establish the rule that ZeroMQ strings are length-specified and are sent on the wire without a trailing null.
These two paragraphs to me are contradictory. Exact what contents are sent by ZeroMQ?
Upvotes: 2
Views: 1658
Reputation: 769
Thanks for all the helps!
I think calling overloaded size_t send (const void *buf_, size_t len_, int flags_ = 0)
instead of bool send (message_t &msg_, int flags_ = 0)
makes the code a little more C++ than C. This is the working version that does not handle exceptions:
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;
}
Upvotes: 3
Reputation: 9117
ZMQ can send and receive raw bytes. It is recommended to use zmq::message_t
instead as it takes care of many edge cases for you and is generally nice to work with.
Look at the implementation of 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 ();
}
It returns true
and this is why your length
equals 1
.
The paragraphs you quoted are not contradictory. It says that you should never assume that the data you received are NULL terminated which means that you shouldn't call printf("%s", request.data())
as printf will likely try to access the memory which isn't allocated. You could use printf("%.*s", (int)request.size(), request.data())
instead however.
After all, ZMQ sends the bytes you tell it to send so basically you can send anything and then receive the message and unpack it to make sense of it (for example when you send multiple sentences in one zmq::message_t
and you use \0
as a delimiter between those sentences).
Upvotes: 1
Reputation: 4386
It seems you are using the functions that returns bool
. So true
converts to 1
.
This explain why you believe you received and sent 1 bytes.
I recommend you call size()
on your message_t
object instead.
Upvotes: 2