MQTT Receive Message in C++ - c++

I'm trying to receive messages from a published topic in C++. I know in Java it's just client.on('message', (topic, message)). But I couldn't do something like that in a C++ library. How can I do it?
As of now, I've got everything set up and am subscribing to the topic I'm interested in, but I'm stuck on how to fetch the message from there.
MQTTClient client;
void mqtt_subscribe(std::string const &topic) {
if(!mqtt_initialized) {
return;
}
MQTTClient_subscribe(client, topic.c_str(), 1);
}

Your client is connected to nothing, so you have to connect first by calling the Mqtt client constructor of the mosquitopp library witch is the top level cpp interface.

Related

How can i send packages on a Minecraft Client (With Fabricmc) and receive it on a Bukkit Server?

I'm a Chinese secondary school student,so my written English may not very well.
How can i send packages (like some words) on a Minecraft Client (Use a Fabricmc Mod to send) and receive it on the bukkit server on MC Multiplayer?
This is done using what's known as the 'plugin messaging channel'. Take a look at this Fabricmc wiki to read about client networking (messaging). See this Spigot wiki on the plugin server-side messaging channel; ignore that this wiki talks a lot about bungee, it's just because that's a common use case. You can make your own channel.
The code below is copied from said wikis and is very much pseudo-code:
Client
Sending from the client
PacketByteBuf buf = PacketByteBufs.create();
buf.writeBlockPos(target);
ServerPlayNetworking.send((ServerPlayerEntity) user, TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, buf);
Receiving on the client
ClientPlayNetworking.registerGlobalReceiver(TutorialNetworkingConstants.HIGHLIGHT_PACKET_ID, (client, handler, buf, responseSender) -> {
client.execute(() -> {
// Everything in this lambda is run on the render thread
ClientBlockHighlighting.highlightBlock(client, target);
});
});
Where you see TutorialNetworkingConstants.HIGHL..., that's the Identifier for the channel.
Server (Spigot/Bukkit)
Sending from the server
player.sendPluginMessage(this, "YourChannelName", out.toByteArray());
Receiving on the server
#Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equals("YourChannelName")) {
return;
}
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String data = in.readUTF();
...
Take a thorough read of those tutorials, they should cover all you need to know. Just be sure to unregister your channels on both the client and server.

How to use libmosquitto to make a request and get response using MQTT v5?

I'm trying to use libmosquitto to make a request (publish to a 'test/topic' topic) and I want to get a response based on the client (sender) id. So that means the client will publish to 'test/topic' and it will automatically subscribe 'test/topic/<client_id>'
The server has already subscribed on 'test/topic' and when it becomes the message, it will send a response (publish) to 'test/topic/<client_id>', which the client subscribed to receive that response in the first place.
The challenge here is how do I get the <client_id>, right. I already done this in python and js, where the client will send metadata or properties in the payload, which the server can unpack to get the client_id. However, I'm using C++ now and it's frustrating because I can't figure out how to get these properties.
Here is an example of how to do this in python. I just want to do the same with c++
I'm using the libmosquitto as I mentionned. I don't even have an example to show because I didn't find how to do this. There is literally no example on how to do this with the mosquitto c++ lib (which is confusing since mosquitto is a famous lib I guess).
I hope someone had a similar problem or can post an example for c++ and mosquitto lib. Thanks in advance.
When in doubt, look at the tests:
const char *my_client_id = ...;
mosquitto_property *proplist = NULL;
mosquitto_property_add_string_pair(&proplist, MQTT_PROP_USER_PROPERTY, "client_id", my_client_id);
mosquitto_publish_v5(mosq, &sent_mid, "test/topic", strlen("message"), "message", 0, false, proplist);
mosquitto_property_free_all(&proplist);
Since you asked in the comments, you can retrieve these properties from published messages by first setting an on_message callback using mosquitto_message_v5_callback_set and the implementing it like so:
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message, const mosquitto_property *props) {
std::string topic{message->topic};
if (topic == "test/topic") {
const char *client_id = nullptr;
mosquitto_property_read_string_pair(props, MQTT_PROP_USER_PROPERTY, nullptr, &client_id, false);
if (client_id) {
/* client_id contains a client id. */
}
}

Auctions in Boost ASIO

I'm implementing an auctioning system in C++ with Boost.Asio. There is a single centralized auctioneer (the server) and some connecting bidders (the clients). I am implementing this in an asynchronous fashion, and I have implemented the basic communication between the bidder and auctioneer (register, ping, get client list). The skeletal code for the auctioneer would look like follows:
class talkToBidder : public boost::enable_shared_from_this<talkToBidder>
{
// Code for sending and receiving messages, which works fine
};
void on_round_end()
{
// Choose the best bid and message the winner
if (!itemList.empty())
timer_reset();
}
void timer_reset()
{
// Send the item information to the bidders
// When the round ends, call on_round_end()
auction_timer.expires_from_now(boost::posix_time::millisec(ROUND_TIME));
auction_timer.async_wait(boost::bind(on_round_end));
}
void handle_accept(...)
{
// Create new bidder...
acceptor.async_accept(bidder->sock(),boost::bind(handle_accept,bidder,_1));
}
int main()
{
// Create new bidder and handle accepting it
talkToBidder::ptr bidder = talkToBidder::new_();
acceptor.async_accept(bidder->sock(),boost::bind(handle_accept,bidder,_1));
service.run();
}
My issue is, I need to wait for at least one bidder to connect before I can start the auction, so I cannot simply call timer_reset() before I use service.run(). What is the Boost.Asio way to go about doing this?
In asynchronous protocol design, it helps to draw Message Sequence Diagrams. Do include your timers.
The code now becomes trivial. You start your timer when the message arrives that should start your timer. Yes, this is shifting the problem a bit forwards. The real point here is that it's not a Boost Asio coding problem. In your case, that particular message appears to be the login of the first bidder, implemented as a TCP connect (SYN/ACK) which maps to handle_accept in your code.

How to receive messages from a streaming server?

I am trying to build an asynchronous gRPC C++ client that sends/receives streaming messages to/from server using the ClientAsyncReaderWriter instance. The client and the server send messages to each other whenever they want. How can I check if there is any message from the server?
The ClientAsyncReaderWriter instance has a binded completion queue. I tried to check the completion queue by calling Next() and AsyncNext() functions to see if there is any event that would indicate that there is some message from the server. However, the completion queue has no events even if there is a message from the server.
class AsyncClient {
public:
AsyncClient(std::shared_ptr<grpc::Channel> channel) :
stub_(MyService::NewStub(channel)),
stream(stub_->AsyncStreamingRPC(&context, &cq, (void *)1))
{}
~AsyncClient()
{}
void receiveFromServer() {
StreamingResponse response;
// 1. Check if there is any message
// 2. Read the message
}
private:
grpc::ClientContext context;
grpc::CompletionQueue cq;
std::shared_ptr<MyService::Stub> stub_;
std::shared_ptr<grpc::ClientAsyncReaderWriter<StreamingRequest, StreamingResponse>> stream;
};
I need to implement steps 1 and 2 in the receiveFromServer() function.
Fortunately, I found a solution to my problem and the asynchronous bi-directional streaming in my project works as expected now.
It turned out that my understanding of the "completion queue" concept was incorrect.
This example was a great help for me!

Does libwebsockets offer publish/subscribe?

I want to create a web application where a group of users could receive some data asynchronously whenever the C++ backend have something new. So, ideally, when a new user comes, he'll be added to the subscribers list and whenever the C++ backend has new data for the group, it will publish it to everybody.
libwebsockets seems to be a good library to use with C++. The only problem is that it seems that it's mainly designed on a callback system, so, apparently data is meant to be sent only if the client asks for it.
I found this post with a similar issue but I don't know if this is the best way to do that: How do I send async data via libwebsocket?
Any help will be appreciated.
Thank you.
found it!
libwebsockets lets you broadcast to all connected users to a specific protocol using libwebsocket_callback_on_writable_all_protocol(*protocol) which triggers LWS_CALLBACK_SERVER_WRITEABLE that will be handled by the protocol's callback function and that's where we could send the data.
So, typically, I use my second protocol (the non-http one) whenever I have some data to broadcast in any part of my code with libwebsocket_callback_on_writable_all_protocol(protocols + 1) and in the protocol's callback function
static int callback_linux_shell(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) {
switch (reason) {
...
case LWS_CALLBACK_SERVER_WRITEABLE:
libwebsocket_write(wsi, my_data, my_data_size, LWS_WRITE_TEXT);
break;
...
}
}