cppzmq
cppzmq copied to clipboard
Zero-Copy or fewer Copies on send and receive
Is there somewhere documentation on how to use zero copy or a minimal amount of allocs and copies when using cppzmq?
I wrote a minimal example that does not work as I expected: Basically, I want to provide to the send and the recv method a buffer that is managed by myself. However, after my recv operation zmq seems to change the content of my buffer concurrently after message_t type is released. Imo it should not do anything with it.
#define NOMINMAX
#include "zmq.hpp"
#include <iostream>
static std::pair<char*, size_t> recv(zmq::socket_t& socket, char* recvBuffer, size_t size)
{
zmq::message_t message(recvBuffer, size);
socket.recv(message);
return { static_cast<char*>(message.data()), message.size() };
}
void send(zmq::socket_t& socket, char* buffer, size_t size)
{
zmq::message_t message(buffer, size);
auto rc = socket.send(message, zmq::send_flags::none);
}
int main(int argc, char *argv[])
{
std::string serverAddr("tcp://localhost:5559");
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REQ);
socket.connect(serverAddr.c_str());
char sendBuffer[]{ 'h', 'e', 'l', 'l', 'o' };
size_t const sendBufferSize = sizeof(sendBuffer);
size_t const recvBufferSize = 300;
char recvBuffer[recvBufferSize];
for(int request = 0; request < 10; request++)
{
send(socket, sendBuffer, sendBufferSize);
auto res = recv(socket, recvBuffer, recvBufferSize);
std::cout << "comment this line to produce correct output" << std::endl;
std::cout << "Received reply " << request << " [" << std::string(res.first, res.second) << "]" << std::endl;
}
}
Output:
Received reply 0 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 1 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 2 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 3 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 4 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 5 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 6 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 7 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 8 [ 6(O¢
▀ ]
comment to produce correct output
Received reply 9 [ 6(O¢
▀ ]
if i comment the line
std::cout << "comment this line to produce correct output" << std::endl;
I get the correct output.
using python as server:
import numpy as np
import zmq
from struct import unpack
port = "5559"
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:%s" % port)
while True:
message = socket.recv(0)
print("Received request: %s" %message)
socket.send_string("World from %s" %port)
Looks a use after free error, returning a pointer to function local data (contents of message) in the recv function.
You are right. But how do I pass my own buffer to a recv so that it's written to my buffer and not somewhere else?
For fixed sized buffers you can do something like this, where data will be written to buf
std::array<std::byte, 1024> buf;
auto ret = socket.recv(zmq::buffer(buf));
// check that ret is valid and not truncated