ZeroMQ server client start sequence - c++11

Facing a issue if the client is started before server
Specs : ubuntu 16.04 with c++11,libzmq : 4.2.3
problem : sample codes
server.cpp
int main()
{
zmq::context_t context(1);
zmq::socket_t requester(context,ZMQ_ROUTER);
.
//code to get address
.
requester.bind(address);
while(true)
{
zmq::message_t message;
requester.recv(&message);
.
//remaining code
.
}
return 0;
}
client.cpp
int main()
{
zmq::context_t context(1);
zmq::socket_t requester(context,ZMQ_DEALER);
.
//code to get address
.
requester.connect(address);
zmq::message_t message;
.
//populate the message to send
.
requester.send(message);
return 0;
}
I know that in zmq i can start client even if the server is not running,but my client application has to include a safety check which requires the server to be started.Is there any way i can achieve by making connect fail or someother workaround.Timeout options doesnt work for me

Make the send non blocking, if there there is no server(s) available the send will fail and set an errno
http://api.zeromq.org/4-2:zmq-send
ZMQ_DONTWAIT
For socket types (DEALER, PUSH) that block when there are no available peers
(or all peers have full high-water mark), specifies that the operation should
be performed in non-blocking mode. If the message cannot be queued on the
socket, the zmq_send() function shall fail with errno set to EAGAIN.

Related

twai/can RX messages receiving is not working is not working in the ESP32-S2 code

SO, I have been trying to test the CAN Bus communication protocol known as "twai" in the esp32-s2 chip.
I have the chip - Arduino wires - can transceiver (SN65HVD230).
Rx is connected to port4
Tx is connected to port5
the receiving of messages is not working and idk why
the following output shows.
Failed to receive message
Message queued for transmission
Failed to receive message
Message queued for transmission
Failed to receive message
Message queued for transmission
Failed to receive message
Message queued for transmission
Failed to receive message
Message queued for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
Failed to receive message
Failed to queue message for transmission
this is the code i used, idk what is wrong in it, i got the commands from the espressif link
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html
it should be similar to the CAN interface in the regular esp32 chip.
this is the code used
#include "driver/gpio.h"
#include "driver/twai.h"
void setup()
{
Serial.begin(115200);
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_5, GPIO_NUM_4, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
{
printf("Driver installed\n");
} else {
printf("Failed to install driver\n");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
printf("Driver started\n");
} else {
printf("Failed to start driver\n");
return;
}
}
void loop() {
//Configure message to transmit
twai_message_t message;
message.identifier =0x12;
message.extd =1;
message.data_length_code = 8;
for (int i = 0; i < 8; i++) {
message.data[i] = 0;
}
//Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
delay(2000);
twai_message_t messagerx;
if (twai_receive(&messagerx, pdMS_TO_TICKS(10000)) == ESP_OK) {
printf("Message received\n");
} else {
printf("Failed to receive message\n");
return;
}
//Process received message
if (messagerx.extd) {
printf("Message is in Extended Format\n");
} else {
printf("Message is in Standard Format\n");
}
printf("ID is %d\n", messagerx.identifier);
if (!(messagerx.rtr)) {
for (int i = 0; i < messagerx.data_length_code; i++) {
printf("Data byte %d = %d\n", i, message.data[i]);
}
}
}
This is currently a known issue with the ESP32-S2 devices where TWAI receive does not function properly, while transmit will function correctly. It effects v4.3 of the ESP-IDF TWAI driver as of writing this answer.
EspressIF will be back porting the fix to v4.3 according to this Github issue; https://github.com/espressif/esp-idf/issues/5604 , however does not yet appear to be complete as the pull request is still marked WIP.
I was able to confirm using similar code to yours by switching back to an ESP32 module and receive would then work correctly.

Ubuntu Mosquitto broker websocket is not working

I'm new at IoT & MQTT communication protocol. I'm trying to connect my broker which runs at Amazon Ec2 from my Vue web app via Websockets. I have started mosquitto with:
root#ip-xxx-xx-xx-xx:~# mosquitto -c /etc/mosquitto/conf.d/default.conf
1618518468: mosquitto version 1.6.7 starting
1618518468: Config loaded from /etc/mosquitto/conf.d/default.conf.
1618518468: Opening ipv4 listen socket on port 1883.
1618518468: Opening ipv6 listen socket on port 1883.
1618518468: Opening websockets listen socket on port 9001.
/etc/mosquitto/conf.d/default.conf file contains:
listener 1883
protocol mqtt
allow_anonymous true
listener 9001
protocol websockets
allow_anonymous true
My test js file is:
var mqtt = require('mqtt');
var count =0;
var client = mqtt.connect("mqtt://xx.xxx.xxx.xxx",{clientId:"mqttjs01"});
console.log("connected flag " + client.connected);
//handle incoming messages
client.on('message',function(topic, message, packet){
console.log("message is "+ message);
console.log("topic is "+ topic);
});
client.on("connect",function(){
console.log("connected "+ client.connected);
})
//handle errors
client.on("error",function(error){
console.log("Can't connect" + error);
process.exit(1)});
//publish
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
//////////////
var options={
retain:true,
qos:1};
var topic="acs";
var message="test message";
var topic_list=["topic2","topic3","topic4"];
var topic_o={"topic22":0,"topic33":1,"topic44":1};
console.log("subscribing to topics");
client.subscribe(topic,{qos:0}); //single topic
client.subscribe(topic_list,{qos:1}); //topic list
client.subscribe(topic_o); //object
var timer_id=setInterval(function(){publish(topic,message,options);},5000);
//notice this is printed even before we connect
console.log("end of script");
But I'm getting this error:
New client connected from 176.xxx.xxx.xx as mqttjs01 (p2, c1, k60).
1618518546: Socket error on client mqttjs01, disconnecting.
I have installed libwebsockets, I have tried with various mosquitto versions. Current version is: 1.6.7.
Is there any problem with my client or broker? How can I fix this?
At the end of the publish() function the if statement is missing enclosing braces so it doesn't do what you think it does.
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
Lets fix the indentation so we can see more clearly.
function publish(topic,msg,options){
console.log("publishing",msg);
if (client.connected == true){
client.publish(topic,msg,options);
}
count+=1;
if (count==2) //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
As you can see client.end() will ALWAYS be called when ever publish() is called. If you only want to publish twice you need to wrap the 2 statements in the braces (this is not python where whitespace has meaning)
if (count==2) { //ens script
clearTimeout(timer_id); //stop timer
client.end();
}
You really should indent all your code properly it will make it much easier to read and to spot errors like this.
Also as #JDAllen mentioned you are not making use of the WebSocket connection, unless this code is running in the browser, where the sandbox will force it to be a WebSocket connection even if you specify mqtt:// as the schema in the URL, and you will have to include the port number to make it actually connect. e.g.
ws://xxx.xxx.xxx.xxx:9001

How to detect a cancelled/lost/closed connection in Cloud Run with gRPC server streaming?

I have a server-side streaming RPC hosted on Google Cloud Run.
With the following proto definition:
syntax = "proto3";
package test.v1;
service MyService {
// Subscribe to a stream of events.
rpc Subscribe (SubscribeRequest) returns (stream SubscribeResponse) {}
}
message SubscribeRequest {
}
message SubscribeResponse {
}
Using BloomRPC/grpcurl, when I stop the method I get a stream.Context().Done() event which I can use to gracefully stop certain tasks. Here is an example of the Suscribe method:
func (s *myService) Subscribe(req *pb.SubscribeRequest, stream pb.Instruments_SubscribeServer) error {
// Create a channel for this client.
ch := make(chan *pb.SubscribeResponse)
// Add the channel object 'ch' to a Global list of channels where we have a 'broadcaster' sending
// messages to all connected clients.
// TODO: pass to broadcaster client list.
for {
select {
case <-stream.Context().Done():
close(ch)
fmt.Println("Removed client from global list of channels")
return nil
case res := <-ch:
_ = stream.Send(res)
}
}
}
On the client side, when I test the service locally (i.e. running a local gRPC server in Golang), using BloomRPC/grpcurl I get a message on the stream.Context().Done() channel whenever I stop the BloomRPC/grpcurl connection. This is the expected behaviour.
However, running the exact same code on Cloud Run in the same way (via BloomRPC/grpcurl), I don't get a stream.Context().Done() message - any reason why this would be different on Google Cloud Run? Looking at the Cloud Run logs, a call to the Subscribe method essentially 'hangs' until the request reaches its timeout.
I needed to enable HTTP/2 Connections in Cloud Run for this to work.

ZMQ - forwarding request between sockets or one-time proxy

I'm struggling with connecting two sockets:
frontend (ROUTER) - which handles clients request and forward them to backend
backend (ROUTER) - which receives request from frontend and deals with them with the use of number of workers ( which require some initialization, configuration etc).
The server code looks like this:
void server_task::run() {
frontend.bind("tcp://*:5570");
backend.bind("inproc://backend");
zmq::pollitem_t items[] = {
{ frontend, 0, ZMQ_POLLIN, 0 },
{ backend, 0, ZMQ_POLLIN, 0}
};
try {
while (true) {
zmq::poll(&items[0], 2, -1);
if (items[0].revents & ZMQ_POLLIN) {
frontend_h();
}
if (items[1].revents & ZMQ_POLLIN) {
backend_h();
}
}
}
catch (std::exception& e) {
LOG(info) << e.what();
}
}
frontend_h and backend_h are handler classes, each having access to both sockets.
The question is:
Considering synchronous execution of frontend_h() and backend_h() how can I forward the request dealt in frontend_h() to backend_h()?
I tried to simply re-send the message using backend socket like that:
void frontend_handler::handle_query(std::unique_ptr<zmq::message_t> identity, std::unique_ptr<zmq::message_t> request) {
zmq::message_t req_msg, req_identity;
req_msg.copy(request.get());
req_identity.copy(identity.get());
zmq::message_t header = create_header(request_type::REQ_QUERY);
backend.send(header, ZMQ_SNDMORE);
backend.send(message);
}
But it stucks on zmq::poll in run() after the execution of handle_query().
Stucks on zmq::poll()?
Your code has instructed the .poll() method to block, exactly as documentation states:
If the value of timeout is -1, zmq_poll() shall block indefinitely until a requested event has occurred...
How can I forward the request?
It seems pretty expensive to re-marshall each message ( +1 for using at least the .copy() method and avoiding re-packing overheads ) once your code is co-located and the first, receiving handler, can request and invoke any appropriate method of the latter directly ( and without any Context()-processing associated efforts and overheads.

boost asio - exclusive binding to the network port

I develop server app using boost asio. App works great. What doesn't work, is the the exclusive binding to the network port.
I launch one instance of the app - it starts listening to incoming connections.
I launch one more instance - it also starts listening to incoming connections on the same port. Handler that passed to async_accept do not invoked with error as expected.
Usually I just try to acquire the port. If operation fails - port is in use. With Asio this approach does not work. How to check availability of the port?
void TcpServerFactory::acceptConnectionsOnPort(int serverPort,
boost::shared_ptr<TcpConfigServerReceiver> tcpConfig,
boost::function<void(boost::shared_ptr<TcpServer>)> onSuccessfullyConnectedHandler)
{
// todo check is port not busy
FORMATTED_LOG(this->_log, info) << "Start to accept connections on port " << serverPort;
auto endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), serverPort);
boost::shared_ptr<boost::asio::ip::tcp::acceptor> tcpAcceptor(new boost::asio::ip::tcp::acceptor(this->_ioService, endpoint));
this->acceptConnections(tcpAcceptor, tcpConfig, onSuccessfullyConnectedHandler);
}
void TcpServerFactory::acceptConnections(boost::shared_ptr<boost::asio::ip::tcp::acceptor> tcpAcceptor,
boost::shared_ptr<TcpConfigServerReceiver> tcpConfig,
boost::function<void(boost::shared_ptr<TcpServer>)> onSuccessfullyConnectedHandler)
{
boost::shared_ptr<boost::asio::ip::tcp::socket> tcpSocket(new boost::asio::ip::tcp::socket(this->_ioService));
boost::function<void(const boost::system::error_code &)> onAcceptOperationCompletedHandler =
boost::bind(&TcpServerFactory::onAcceptOperationCompleted, this->downcasted_shared_from_this<TcpServerFactory>(),
_1, tcpAcceptor, tcpSocket, tcpConfig, onSuccessfullyConnectedHandler);
tcpAcceptor.get()->async_accept(*tcpSocket, onAcceptOperationCompletedHandler);
}
void TcpServerFactory::onAcceptOperationCompleted(const boost::system::error_code & err,
boost::shared_ptr<boost::asio::ip::tcp::acceptor> tcpAcceptor,
boost::shared_ptr<boost::asio::ip::tcp::socket> tcpSocket,
boost::shared_ptr<TcpConfigServerReceiver> tcpConfig,
boost::function<void(boost::shared_ptr<TcpServer>)> onSuccessfullyConnectedHandler)
{
if (err)
{
FORMATTED_LOG(this->_log, info) << "Failed to accept connections on port " << tcpAcceptor->local_endpoint().port() << "due to error " << BOOST_ERROR_TO_STREAM(err);
return;
}
this->acceptConnections(tcpAcceptor, tcpConfig, onSuccessfullyConnectedHandler);
this->onConnectionEstablished(tcpSocket, tcpConfig, onSuccessfullyConnectedHandler);
}
Update
I tried to replace constructor of acceptor on series of commands. I expected that on tcpAcceptor->bind() exception will be raised, but that didn't happened.
// boost::shared_ptr<boost::asio::ip::tcp::acceptor> tcpAcceptor(new boost::asio::ip::tcp::acceptor(this->_ioService, endpoint));
boost::shared_ptr<boost::asio::ip::tcp::acceptor> tcpAcceptor(new boost::asio::ip::tcp::acceptor(this->_ioService));
tcpAcceptor->open(endpoint.protocol());
tcpAcceptor->set_option(boost::asio::socket_base::reuse_address(true));
tcpAcceptor->bind(endpoint);
boost::system::error_code err;
tcpAcceptor->listen(boost::asio::socket_base::max_connections, err);
reuse_address is not supposed to do that. Its meaning to avoid "wait" interval after port was freed.

Resources