mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2025-06-20 18:57:59 +02:00
zmq sender and receiver examples
This commit is contained in:
188
network_io/src/ZmqHeader.cpp
Normal file
188
network_io/src/ZmqHeader.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
|
||||
#include "aare/ZmqHeader.hpp"
|
||||
|
||||
#include "simdjson.h"
|
||||
|
||||
using namespace simdjson;
|
||||
|
||||
// helper functions to write json
|
||||
// append to string for better performance (not tested)
|
||||
|
||||
/**
|
||||
* @brief write a digit to a string
|
||||
* takes key and value and outputs->"key": value,
|
||||
* @tparam T type of value (int, uint32_t, ...)
|
||||
* @param s string to append to
|
||||
* @param key key to write
|
||||
* @param value value to write
|
||||
* @return void
|
||||
* @note
|
||||
* - can't use concepts here because we are using c++17
|
||||
*/
|
||||
template <typename T> void write_digit(std::string &s, const std::string &key, const T &value) {
|
||||
s += "\"";
|
||||
s += key;
|
||||
s += "\": ";
|
||||
s += std::to_string(value);
|
||||
s += ", ";
|
||||
}
|
||||
void write_str(std::string &s, const std::string &key, const std::string &value) {
|
||||
s += "\"";
|
||||
s += key;
|
||||
s += "\": \"";
|
||||
s += value;
|
||||
s += "\", ";
|
||||
}
|
||||
void write_map(std::string &s, const std::string &key, const std::map<std::string, std::string> &value) {
|
||||
s += "\"";
|
||||
s += key;
|
||||
s += "\": {";
|
||||
for (auto &kv : value) {
|
||||
write_str(s, kv.first, kv.second);
|
||||
}
|
||||
s += "}, ";
|
||||
}
|
||||
void write_array(std::string &s, const std::string &key, const std::array<int, 4> &value) {
|
||||
s += "\"";
|
||||
s += key;
|
||||
s += "\": [";
|
||||
s += std::to_string(value[0]);
|
||||
s += ", ";
|
||||
s += std::to_string(value[1]);
|
||||
s += ", ";
|
||||
s += std::to_string(value[2]);
|
||||
s += ", ";
|
||||
s += std::to_string(value[3]);
|
||||
s += "], ";
|
||||
}
|
||||
|
||||
namespace aare {
|
||||
|
||||
std::string ZmqHeader::to_string() const {
|
||||
std::string s = "";
|
||||
s.reserve(1024);
|
||||
s += "{";
|
||||
write_digit(s, "data", data ? 1 : 0);
|
||||
write_digit(s, "jsonversion", jsonversion);
|
||||
write_digit(s, "dynamicRange", dynamicRange);
|
||||
write_digit(s, "fileIndex", fileIndex);
|
||||
write_digit(s, "ndetx", ndetx);
|
||||
write_digit(s, "ndety", ndety);
|
||||
write_digit(s, "npixelsx", npixelsx);
|
||||
write_digit(s, "npixelsy", npixelsy);
|
||||
write_digit(s, "imageSize", imageSize);
|
||||
write_digit(s, "acqIndex", acqIndex);
|
||||
write_digit(s, "frameIndex", frameIndex);
|
||||
write_digit(s, "progress", progress);
|
||||
write_str(s, "fname", fname);
|
||||
write_digit(s, "frameNumber", frameNumber);
|
||||
write_digit(s, "expLength", expLength);
|
||||
write_digit(s, "packetNumber", packetNumber);
|
||||
write_digit(s, "detSpec1", detSpec1);
|
||||
write_digit(s, "timestamp", timestamp);
|
||||
write_digit(s, "modId", modId);
|
||||
write_digit(s, "row", row);
|
||||
write_digit(s, "column", column);
|
||||
write_digit(s, "detSpec2", detSpec2);
|
||||
write_digit(s, "detSpec3", detSpec3);
|
||||
write_digit(s, "detSpec4", detSpec4);
|
||||
write_digit(s, "detType", detType);
|
||||
write_digit(s, "version", version);
|
||||
write_digit(s, "flipRows", flipRows);
|
||||
write_digit(s, "quad", quad);
|
||||
write_digit(s, "completeImage", completeImage ? 1 : 0);
|
||||
write_map(s, "addJsonHeader", addJsonHeader);
|
||||
write_array(s, "rx_roi", rx_roi);
|
||||
// remove last comma
|
||||
s.pop_back();
|
||||
s.pop_back();
|
||||
|
||||
s += "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
void ZmqHeader::from_string(std::string &s) {
|
||||
|
||||
simdjson::padded_string ps(s.c_str(), s.size());
|
||||
ondemand::parser parser;
|
||||
ondemand::document doc = parser.iterate(ps);
|
||||
ondemand::object object = doc.get_object();
|
||||
|
||||
for (auto field : object) {
|
||||
std::string_view key = field.unescaped_key();
|
||||
|
||||
if (key == "data") {
|
||||
data = uint64_t(field.value()) ? true : false;
|
||||
} else if (key == "jsonversion") {
|
||||
jsonversion = uint32_t(field.value());
|
||||
} else if (key == "dynamicRange") {
|
||||
dynamicRange = uint32_t(field.value());
|
||||
} else if (key == "fileIndex") {
|
||||
fileIndex = uint64_t(field.value());
|
||||
} else if (key == "ndetx") {
|
||||
ndetx = uint32_t(field.value());
|
||||
} else if (key == "ndety") {
|
||||
ndety = uint32_t(field.value());
|
||||
} else if (key == "npixelsx") {
|
||||
npixelsx = uint32_t(field.value());
|
||||
} else if (key == "npixelsy") {
|
||||
npixelsy = uint32_t(field.value());
|
||||
} else if (key == "imageSize") {
|
||||
imageSize = uint32_t(field.value());
|
||||
} else if (key == "acqIndex") {
|
||||
acqIndex = uint64_t(field.value());
|
||||
} else if (key == "frameIndex") {
|
||||
frameIndex = uint64_t(field.value());
|
||||
} else if (key == "progress") {
|
||||
progress = field.value().get_double();
|
||||
} else if (key == "fname") {
|
||||
std::string_view tmp = field.value().get_string();
|
||||
fname = {tmp.begin(), tmp.end()};
|
||||
} else if (key == "frameNumber") {
|
||||
frameNumber = uint64_t(field.value());
|
||||
} else if (key == "expLength") {
|
||||
expLength = uint32_t(field.value());
|
||||
} else if (key == "packetNumber") {
|
||||
packetNumber = uint32_t(field.value());
|
||||
} else if (key == "detSpec1") {
|
||||
detSpec1 = uint64_t(field.value());
|
||||
} else if (key == "timestamp") {
|
||||
timestamp = uint64_t(field.value());
|
||||
} else if (key == "modId") {
|
||||
modId = uint32_t(field.value());
|
||||
} else if (key == "row") {
|
||||
row = uint32_t(field.value());
|
||||
} else if (key == "column") {
|
||||
column = uint32_t(field.value());
|
||||
} else if (key == "detSpec2") {
|
||||
detSpec2 = uint32_t(field.value());
|
||||
} else if (key == "detSpec3") {
|
||||
detSpec3 = uint32_t(field.value());
|
||||
} else if (key == "detSpec4") {
|
||||
detSpec4 = uint32_t(field.value());
|
||||
} else if (key == "detType") {
|
||||
detType = uint32_t(field.value());
|
||||
} else if (key == "version") {
|
||||
version = uint32_t(field.value());
|
||||
} else if (key == "flipRows") {
|
||||
flipRows = uint32_t(field.value());
|
||||
} else if (key == "quad") {
|
||||
quad = uint32_t(field.value());
|
||||
} else if (key == "completeImage") {
|
||||
completeImage = uint64_t(field.value()) ? true : false;
|
||||
} else if (key == "addJsonHeader") {
|
||||
for (auto field2 : field.value().get_object()) {
|
||||
simdjson::ondemand::raw_json_string tmp;
|
||||
auto error = field2.key().get(tmp);
|
||||
std::string key2(tmp.raw());
|
||||
std::string val;
|
||||
error = field2.value().get_string(val);
|
||||
addJsonHeader[key2] = std::string(val);
|
||||
}
|
||||
} else if (key == "rx_roi") {
|
||||
rx_roi = std::array<int, 4>(field.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aare
|
26
network_io/src/ZmqSocket.cpp
Normal file
26
network_io/src/ZmqSocket.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "aare/ZmqSocket.hpp"
|
||||
#include <fmt/core.h>
|
||||
#include <zmq.h>
|
||||
|
||||
namespace aare {
|
||||
|
||||
void ZmqSocket::disconnect() {
|
||||
zmq_close(m_socket);
|
||||
zmq_ctx_destroy(m_context);
|
||||
m_socket = nullptr;
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
ZmqSocket::~ZmqSocket() {
|
||||
if (m_socket)
|
||||
disconnect();
|
||||
delete[] m_header_buffer;
|
||||
}
|
||||
|
||||
void ZmqSocket::set_zmq_hwm(int hwm) { m_zmq_hwm = hwm; }
|
||||
|
||||
void ZmqSocket::set_timeout_ms(int n) { m_timeout_ms = n; }
|
||||
|
||||
void ZmqSocket::set_potential_frame_size(size_t size) { m_potential_frame_size = size; }
|
||||
|
||||
} // namespace aare
|
@ -1,10 +1,13 @@
|
||||
#include "aare/ZmqSocketReceiver.hpp"
|
||||
#include "aare/utils/logger.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <zmq.h>
|
||||
|
||||
namespace aare {
|
||||
|
||||
ZmqSocketReceiver::ZmqSocketReceiver(const std::string &endpoint) : m_endpoint(endpoint) {
|
||||
ZmqSocketReceiver::ZmqSocketReceiver(const std::string &endpoint) {
|
||||
m_endpoint = endpoint;
|
||||
memset(m_header_buffer, 0, m_max_header_size);
|
||||
}
|
||||
|
||||
@ -16,7 +19,7 @@ void ZmqSocketReceiver::connect() {
|
||||
if (rc)
|
||||
throw std::runtime_error(fmt::format("Could not set ZMQ_RCVHWM: {}", strerror(errno)));
|
||||
|
||||
int bufsize = 1024 * 1024 * m_zmq_hwm;
|
||||
int bufsize = m_potential_frame_size * m_zmq_hwm;
|
||||
fmt::print("Setting ZMQ_RCVBUF to: {} MB\n", bufsize / (1024 * 1024));
|
||||
rc = zmq_setsockopt(m_socket, ZMQ_RCVBUF, &bufsize, sizeof(bufsize));
|
||||
if (rc)
|
||||
@ -26,37 +29,27 @@ void ZmqSocketReceiver::connect() {
|
||||
zmq_setsockopt(m_socket, ZMQ_SUBSCRIBE, "", 0);
|
||||
}
|
||||
|
||||
void ZmqSocketReceiver::disconnect() {
|
||||
zmq_close(m_socket);
|
||||
zmq_ctx_destroy(m_context);
|
||||
m_socket = nullptr;
|
||||
m_context = nullptr;
|
||||
}
|
||||
int ZmqSocketReceiver::receive(ZmqHeader &header, std::byte *data, bool serialized_header) {
|
||||
|
||||
ZmqSocketReceiver::~ZmqSocketReceiver() {
|
||||
if (m_socket)
|
||||
disconnect();
|
||||
delete[] m_header_buffer;
|
||||
}
|
||||
if (serialized_header)
|
||||
throw std::runtime_error("Not implemented");
|
||||
|
||||
void ZmqSocketReceiver::set_zmq_hwm(int hwm) { m_zmq_hwm = hwm; }
|
||||
|
||||
void ZmqSocketReceiver::set_timeout_ms(int n) { m_timeout_ms = n; }
|
||||
|
||||
int ZmqSocketReceiver::receive(zmqHeader &header, std::byte *data) {
|
||||
int header_bytes_received = zmq_recv(m_socket, m_header_buffer, m_max_header_size, 0);
|
||||
|
||||
// receive header
|
||||
int header_bytes_received = zmq_recv(m_socket, m_header_buffer, m_max_header_size, 0);
|
||||
m_header_buffer[header_bytes_received] = '\0'; // make sure we zero terminate
|
||||
if (header_bytes_received < 0) {
|
||||
fmt::print("Error receiving header: {}\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fmt::print("Bytes: {}, Header: {}\n", header_bytes_received, m_header_buffer);
|
||||
aare::logger::debug("Bytes: ", header_bytes_received, ", Header: ", m_header_buffer);
|
||||
|
||||
// decode header
|
||||
if (!decode_header(header)) {
|
||||
fmt::print("Error decoding header\n");
|
||||
// parse header
|
||||
try {
|
||||
std::string header_str(m_header_buffer);
|
||||
header.from_string(header_str);
|
||||
} catch (const simdjson::simdjson_error &e) {
|
||||
aare::logger::error(LOCATION + "Error parsing header: ", e.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -67,16 +60,13 @@ int ZmqSocketReceiver::receive(zmqHeader &header, std::byte *data) {
|
||||
if (!more) {
|
||||
return 0; // no data following header
|
||||
} else {
|
||||
int data_bytes_received = zmq_recv(m_socket, data, 1024 * 1024 * 2, 0); // TODO! configurable size!!!!
|
||||
|
||||
int data_bytes_received = zmq_recv(m_socket, data, header.imageSize, 0); // TODO! configurable size!!!!
|
||||
if (data_bytes_received == -1)
|
||||
throw std::runtime_error("Got half of a multipart msg!!!");
|
||||
aare::logger::debug("Bytes: ", data_bytes_received);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool ZmqSocketReceiver::decode_header(zmqHeader &h) {
|
||||
// TODO: implement
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace aare
|
||||
|
32
network_io/src/ZmqSocketSender.cpp
Normal file
32
network_io/src/ZmqSocketSender.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "aare/ZmqSocketSender.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <zmq.h>
|
||||
|
||||
namespace aare {
|
||||
ZmqSocketSender::ZmqSocketSender(const std::string &endpoint) { m_endpoint = endpoint; }
|
||||
|
||||
void ZmqSocketSender::bind() {
|
||||
m_context = zmq_ctx_new();
|
||||
m_socket = zmq_socket(m_context, ZMQ_PUB);
|
||||
int rc = zmq_bind(m_socket, m_endpoint.c_str());
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
int ZmqSocketSender::send(ZmqHeader &header, const std::byte *data, size_t size, bool serialize_header) {
|
||||
int rc;
|
||||
if (serialize_header) {
|
||||
rc = zmq_send(m_socket, &header, sizeof(ZmqHeader), ZMQ_SNDMORE);
|
||||
assert(rc == sizeof(ZmqHeader));
|
||||
} else {
|
||||
std::string header_str = header.to_string();
|
||||
rc = zmq_send(m_socket, header_str.c_str(), header_str.size(), ZMQ_SNDMORE);
|
||||
assert(rc == header_str.size());
|
||||
}
|
||||
|
||||
int rc2 = zmq_send(m_socket, data, size, 0);
|
||||
assert(rc2 == size);
|
||||
return rc + rc2;
|
||||
}
|
||||
|
||||
} // namespace aare
|
Reference in New Issue
Block a user