I'm trying to write a handler class that subscribes to a message published via zeromq and buffers the last received message.
I tried doing this as follows. The method ReceivedMessage() is to be called by a wrapper application in a cyclic called function. Once it returns true, I tried to access the message using GetReceivedMessageData(). Unfortunately, it seems that the data is not saved properly in the member zmq_receivedMessage_.
I guess this is because of zmq_receivedMessage_ being initialized with fixed size and the call zmq_subscriber_.recv(&zmq_receivedMessage_) does not automatically resize it?
What would be the easiest and most robust way to this? The only way I can think of is using realloc() and memcpy() every time a new message is received. Or is there a simpler way?
#include <cstdint>
#include "zeromq_cpp/zmq.hpp"
class HandlerClass
{
public:
/// #brief Initializes a AirSimToRos class instance.
HandlerClass(std::string const& addr);
// #brief Gets the message data received via ZeroMq as pointer.
void* GetReceivedMessageData();
// #brief Gets the message size received via ZeroMq as size_t.
std::size_t GetReceivedMessageSize();
// #brief Returns true if a new, full message was received via ZeroMq, false otherwise
bool ReceivedMessage();
private:
/// #brief A ZeroMq context object encapsulating functionality dealing with the initialisation and termination.
zmq::context_t zmq_context_;
/// #brief A ZeroMq socket for subscribing to incoming messages.
zmq::socket_t zmq_subscriber_;
/// #brief A ZeroMq message that was received last. Might be empty if ReceivedMessage() never was true.
zmq::message_t zmq_receivedMessage_;
};
HandlerClass::HandlerClass(std::string const& addr)
: zmq_context_(1)
, zmq_subscriber_(zmq_context_, ZMQ_SUB)
{
zmq_subscriber_.setsockopt(ZMQ_IDENTITY, "HandlerSubscriber", 5);
zmq_subscriber_.setsockopt(ZMQ_SUBSCRIBE, "", 0);
zmq_subscriber_.setsockopt(ZMQ_RCVTIMEO, 5000);
zmq_subscriber_.connect(addr);
}
void* HandlerClass::GetReceivedMessageData()
{
return zmq_receivedMessage_.data();
}
std::size_t HandlerClass::GetReceivedMessageSize()
{
return zmq_receivedMessage_.size();
}
bool HandlerClass::ReceivedMessage()
{
int received_bytes = zmq_subscriber_.recv(&zmq_receivedMessage_);
return received_bytes > 0;
}
One way would be a redesign w/ Poller-instance + ZMQ_CONFLATE
Having zero context of the intended class use-cases, the original design seems to be a rather "mechanical" wrapper of a data-mover, not any MVP-slim-design, that can squeeze maximum of the benefits the ZeroMQ Scalable Formal Communication Archetypes Signalling/Messaging framework has already built-in.
The much smarter ( and also a ZMQ_RCV_HWM-safer ( goes beyond the scope of this topic ) ) would be not to just always mechanically read each message from the ZeroMQ Context-domain of control, unless in a real need to re-transmit such data from the HandlerClass somewhere further down the line.
Add a private instance of the Poller that would allow to redesign data-flow mechanics -- using non-destructive query, using a .poll()-method for testing a new message arrival ( having also a Real-Time / Event-Handling Loop stability control tools, not to wait longer than an ad-hoc set .poll()-method timeout ), while yet able to defer any actual data-move as late as possible, until a data indeed need to flow outside of the HandlerClass-instance, not anywhere earlier.
HandlerClass::HandlerClass(std::string const& addr)
: zmq_context_(1)
, zmq_subscriber_(zmq_context_, ZMQ_SUB)
{
zmq_subscriber_.setsockopt( ZMQ_IDENTITY, "HandlerSubscriber", 5 );
zmq_subscriber_.connect( addr );
zmq_subscriber_.setsockopt( ZMQ_SUBSCRIBE, "", 0 );
zmq_subscriber_.setsockopt( ZMQ_LINGER, 0 ); // ALWAYS, READY 4 .term()
zmq_subscriber_.setsockopt( ZMQ_CONFLATE, 1 ); // SMART
zmq_subscriber_.setsockopt( ZMQ_TOS, T ); // WORTH DEPLOY & MANAGE
zmq_subscriber_.setsockopt( ZMQ_RCVTIMEO, 5000 );
// ------------------------------------------------- // ADD Poller-instance
...
// ------------------------------------------------- // RTO
}
Nota Bene: In case the exgress flow is also made on ZeroMQ infrastructure, there are time-saving API tools for Zero-Copy message re-marshalling into another ZeroMQ socket-transport -- ( almost ) for free -- cool, isn't it?
Related
I am designing an API interface for Arinc429 devices. Various suppliers provide different features within devices, so I decided to have a set of common and expected methods that must be implemented for every entity.
In particular, I have a question regarding the output channel. It provides a method for a single output of a byte array, and the output itself is asynchronous after the method is called. One of the devices implements interrupts which can be caught via OS utilities (WaitForSingleObject in Windows).
So in this particular case I have an object which implements IArinc429Device, it:
implements method CaptureInterrupt that invokes a particular channel's callback when interrupt occurs;
holds a thread that runs CaptureInterrupt;
void ArincPCI429_3::CaptureInterrupt()
{
HANDLE hEvent = CreateEvent(nullptr, TRUE, FALSE, "PCI429_3Interrupt");
// register event handle within device via DeviceIoControl
while (true)
{
DWORD waitRes = WaitForSingleObject(hEvent, INFINITE);
ResetEvent(hEvent);
// get output channel index which has generated an interrupt
size_t channelIndex = ...;
// private implementation holds pointers to output channels
pImpl_->GetChannelOut(channelIndex)->InvokeInterrupCallback();
}
}
But another device does not implement interrupts, so I have to "busy-wait" (sleep for the calculated expected time, then loop sleeping for small periods of time to adjust possible inaccuracies).
An object that implements interface IArinc429ChannelOutput:
implements method SingleOutput, that initiates asynchronous output;
implements method WaitOutputFinished, that waits until channel is running, then modifies its state to stopped;
holds a thread that runs WaitOutputFinished;
void ArincECE206_1ChannelOutput::WaitOutputFinished(size_t words)
{
// calculate expected period of time to sleep, using amount of words to transfer and channel output speed
std::chrono::microseconds timeToSleep = ...;
// 99% is enough
std::this_thread::sleep_for(timeToSleep);
// if channel is still running, wait for 1 more word.
timeToSleep = Arinc429Values::TimeToTransfer(
refImpl_.outputFreqs[ChannelIndex()],
1);
while(IsRunning())
{
std::this_thread::sleep_for(timeToSleep);
++additionalWords;
}
mode_ = Arinc429OutMode::stopped;
if (callbackOnFinishedOutput_)
callbackOnFinishedOutput_();
}
Here is part of an API for output channel
struct ARINC429_API IArinc429ChannelOutput
{
// 0 based index
virtual size_t ChannelIndex() const = 0;
virtual Arinc429OutMode OutputMode() const = 0;
virtual Arinc429Freq Frequency() const = 0;
virtual size_t BufferSize() const = 0;
virtual void SetFinishOutputCallback(std::function<void()>&& fCallBack) = 0;
// elements exceeding BufferSize are ignored
// TODO: return future?
virtual bool SingleOutput(array_view<const uint32_t> wordArray) = 0;
virtual void StopOutput() = 0;
virtual ~IArinc429ChannelOutput() = default;
};
Given the asynchronous nature of output, I think it would be convenient to return std::future from SingleOutput. And I see no problem in doing so for the second type of an Arinc429 device, since separate channel objects own their own separate waiting threads.
I chose to add a callback on finished output from the beginning since interrupts are implemented for the first device. Also callbacks are convenient to emit Qt signals from.
But std::future is more handy for synchronization and can be used to wait for an output to finish. Though it is also manageable using callbacks and condition variables, I do not find that approach rather convenient.
What option to choose?
a. Define routine that registers and uses callbacks.
b. Define std::future as a return type for SingleOutput.
c. Define both. Is this reasonable or even possible? It implies calling std::promise<R>::set_value and than calling.
Another question is about implementation.
I don't see a clear and simple way to implement returning std::future in case of a device that implements interrupts, since there is a common interrupt event and capturing thread for all the channels.
How to provide futures for multiple output channel objects which all reside in different threads? See ArincPCI429_3::CaptureInterrupt()
I've asked this question before I got familiar with ASIO and Executors. They provide a Universal Asynchronous Model API. That is, a template function can be both synchronous and asynchronous depending on a completion token.
Basically, a function would look like
template <typename CompletionT>
auto do_stuff(CompletionT &&token);
Depending on the type of a token, there result can be returned via a simple callback:
do_stuff([](bool res){ return res;});
If an synchronous behavior is needed, a special tag can be passed instead:
auto boolFuture = do_stuff(use_future);
bool res = boolFuture.get();
I am implementing a connection multiplexer - class, which wraps a single connection in order to provide an ability to create so-called Stream-s over it. There can be dozens of such streams over one physical connection.
Messages sent over that connection are defined by a protocol and can be service ones (congestion control, etc), which are never seen by the clients, and data ones - they contain some data for the streams, for which one - defined in the header of the corresponding message.
I have encountered a problem when implementing a method read for a Stream. It must be blocking, but asynchronous, so that it returns some value - data read or error happened - but the request itself must be is some kind of async queue.
To implement asynchronous network IO we have used Boost's async_read-s, async_write-s, etc with a completion token, taken from another library. So, a call to MyConnection::underlying_connection::read(size_t) is asynchronous already in the terms I described before.
One solution I have implemented is function MyConnection::processFrame(), which is reading from the connection, processing message and, if it is a data message, puts the data into the corresponding stream's buffer. The function is to be called in a while loop by the stream's read. But, in that case there can be more than one simulteneous calls to async_read, which is UB. Also, this would mean that even service messages are to wait until some stream wants to read the data, which is not appropriate as well.
Another solution I came up is using future-s, but as I checked, their methods wait/get would block the whole thread (even with defered policy or paired promise), which must be avoided too.
Below is a simplified example with only methods, which are needed to understand the question. This is current implementation, which contains bugs.
struct LowLevelConnection {
/// completion token of 3-rd part library - ufibers
yield_t yield;
/// boost::asio socket
TcpSocket socket_;
/// completely async (in one thread) method
std::vector<uint8_t> read(size_t bytes) {
std::vector<uint8_t> res;
res.reserve(bytes);
boost::asio::async_read(socket_, res, yield);
return res;
}
}
struct MyConnection {
/// header is always of that length
constexpr uint32_t kHeaderSize = 12;
/// underlying connection
LowLevelConnection connection_;
/// is running all the time the connection is up
void readLoop() {
while (connection_.isActive()) {
auto msg = connection_.read(kHeaderSize);
if (msg.type == SERVICE) { handleService(msg); return; }
// this is data message; read another part of it
auto data = connection_.read(msg.data_size);
// put the data into the stream's buffer
streams_.find(data.stream_id).buffer.put(data);
}
}
}
struct Stream {
Buffer buffer;
// also async blocking method
std::vector<uint8_t> read(uint32_t bytes) {
// in perfect scenario, this should look like this
async_wait([]() { return buffer.size() >= bytes; });
// return the subbuffer of 'bytes' size and remove them
return subbufer...
}
}
Thanks for future answers!
I'm using a C library which rips PDF data and provides me with that data via callbacks. Two callbacks are used, one which provides me with the job header and another which provides me with the the ripped data ranging from 1 - 50MB chunks.
I'm then taking that data and sending it across the wire via TCP to someone who cares.
I'm using the boost async_write to send that data across the wire. I want to synchronize access to the async_write until it's done sending the previous chunk of data.
The C callback functions:
void __stdcall HeaderCallback( void* data, int count )
{
// The Send function is a member of my AsyncTcpClient class.
// This is how I'm currently providing my API with the PDF data.
client.Send( data, count );
}
void __stdcall DataCallback( void* data, int count )
{
client.Send( data, count );
}
I receive the provided data in my AsyncTcpClient class's Send method.
void AsyncTcpClient::Send( void* buffer, size_t length )
{
// Write to the remote server.
boost::asio::async_write( _session->socket,
boost::asio::buffer( ( const char* )buffer, length ),
[ this ]( boost::system::error_code const& error, std::size_t bytesTransfered )
{
if ( error )
{
_session->errorCode = error;
OnRequestComplete( _session );
return;
}
std::unique_lock<std::mutex> cancelLock( _session->cancelGuard );
if ( _session->cancelled )
{
OnRequestComplete( _session );
return;
}
} );
}
How can I synchronize access to the async_write function?
Using a mutex at the start of the Send function would be pointless as the async_write returns immediately.
It's also pointless to store the mutex in a unique_lock member variable and attempt to unlock it in the async_write callback lambda as that'll blow up.
How can I synchronize access to the async_write function without using strand?
The first iteration of the program wont use strand for synchronization, I will be implementing that later.
You should use an io_context::strand.
One example from many others, but that answer will help you.
I have a multi-threaded C++ app using lib event. The receive all happens in the libevent process and then a flag is set so that the data received is processed later. On the send tho, things go wrong. I am in a "main thread" and the data to send is assembled and then the following function is invoked.
int SocketWrapper :: SendData( const U8* buffer, int length )
{
if( m_useLibeventToSend )
{
bufferevent* bev = GetBufferEvent();
struct evbuffer* outputBuffer = bufferevent_get_output( bev );
evbuffer_lock( outputBuffer );
int result = evbuffer_add( outputBuffer, buffer, length );
evbuffer_unlock( outputBuffer );
return result;
}
return send( m_socketId, (const char* )buffer, length, 0 );
}
This function crashes on occasion at the point of the evbuffer_add invocation but 99.9% of the time it works fine. This smells like a concurrency bug and it may be related to clients crashing or coming-and-going. I made sure that during the initial creation of the socket by libevent, I did the following:
struct evbuffer* outputBuffer = bufferevent_get_output( GetBufferEvent() );
evbuffer_enable_locking( outputBuffer, NULL );
Do you have any notion of some other special initialization I should be doing? Should I not invoke "SendData" from my main thread and instead send an event to the bufferevent so that the send should happen in the same process as libevent?
All design ideas are open. So far, my workaround is to not use libevent for the send, but to write directly to the socket.
This crash happens in both release and debug, VS 2008, libevent 2.0. It's deep in the library so I will be resorting to including the c files in my project to try and track down my problem, but maybe someone here knows instantly what's wrong. :-)
Okay, I actually don't have code as of yet because i'm just picking out a framework for the time being, but i'm still a little baffled about how i wish to go about this :.
Server side, i wish to have a class where each instance has a socket and various information identifying each connection. each object will have it's own thread for receiving data. I understand how i'll be implementing most of that, but my confusion starts just as i get to the actual transfer of data between server and client. I'll want to have a bunch of different message structs for specific cases, (for example CONNECT_MSG , DISCONNECT_MSG, POSTTEXT_MSG, etc) and then all i have to do is have a char * point at that struct and then pass it via the send() function.
But as i think on it, it gets a little complicated at that point. Any of those different message types could be sent, and on the receiving end, you will have no idea what you should cast the incoming buffer as. What i was hoping to do is, in the thread of each connection object, have it block until it receives a packet with a message, then dump it into a single queue object managed by the server(mutexes will prevent greediness) and then the server will process each message in FIFO order independent of the connection objects.
I havn't written anything yet, but let me write a little something to illustrate my setup.
#define CONNECT 1000
struct GENERIC_MESSAGE
{
int id;
}
struct CONNECT_MESSAGE : public GENERIC_MESSAGE
{
m_username;
}
void Connection::Thread()
{
while(1)
{
char buffer[MAX_BUFFER_SIZE]; // some constant(probably 2048)
recv(m_socket, buffer, MAX_BUFFER_SIZE, 0);
MESSAGE_GENERIC * msg = reinterpret_cast<MESSAGE_GENERIC *> (buffer);
server->queueMessage(msg);
}
}
void Server::QueueMessage(MESSAGE_GENERIC * msg)
{
messageQueue.push(msg);
}
void Server::Thread()
{
while(1)
{
if(!messageQueue.empty())
ProcessMessages();
else
Sleep(1);
}
}
void Server::ProcessMessages()
{
for(int i = 0; i < messageQueue.size(); i++)
{
switch(messageQueue.front()->id)
{
case CONNECT:
{
// the part i REALLY don't like
CONNECT_MESSAGE * msg = static_cast<CONNECT_MESSAGE *>(messageQueue.front() );
// do the rest of the processing on connect
break;
}
// other cases for the other message types
}
messageQueue.pop();
}
}
Now if you've been following up until now, you realize just how STUPID and fragile this is. it casts to the base class, passes that pointer to a queue, and then just assumes that the pointer is still valid from the other thread, and even then whether or not the remaining buffer after the pointer for the rest of the derived class will always be valid afterward for casting, but i have yet to find a correct way of doing this. I am wide open for ANY suggestions, either making this work, or an entirely different messaging design.
Before you write even a line of code, design the protocol that will be used on the wired. Decide what a message will consist of at the byte level. Decide who sends first, whether messages are acknowledged, how receivers identify message boundaries, and so on. Decide how the connection will be kept active (if it will be), which side will close first, and so on. Then write the code around the specification.
Do not tightly associate how you store things in memory with how you send things on the wire. These are two very different things with two very different sets of requirements.
Of course, feel free to adjust the protocol specification as you write the code.