I am experimenting with libmosquitto-dev on Raspbian and having some issues.
My code works absolutely fine so far. I can connect to a broker and once the topic gets an update my programm prints the message as it should.
It's just the point when the broker dies after connection and gets restarted.
My code realize the connection dropped and tries to reconnect. Once the broker is back online my code reconnects. But from this on it does not print any updates on the channel.
Why not? I thought this would catch up the connection fine, but it does not.
Her's my code:
[...]
static int run = 1;
void connect_callback(struct mosquitto *mosq, void *obj, int result)
{
printf("connect callback, rc=%d\n", result);
}
void message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
bool match = 0;
printf("got message '%.*s' for topic '%s'\n", message->payloadlen, (char*) message->payload, message->topic);
mosquitto_topic_matches_sub("Heizung", message->topic, &match);
if (match) {
printf("got message for HEIZUNG topic\n");
}
}
int main(int argc, char *argv[])
{
uint8_t reconnect = true;
char clientid[24];
struct mosquitto *mosq;
int rc = 0;
mosquitto_lib_init();
memset(clientid, 0, 24);
snprintf(clientid, 23, "mylog_%d", getpid());
mosq = mosquitto_new(clientid, true, 0);
if(mosq){
mosquitto_connect_callback_set(mosq, connect_callback);
mosquitto_message_callback_set(mosq, message_callback);
rc = mosquitto_connect(mosq, mqtt_host, mqtt_port, 60);
mosquitto_subscribe(mosq, NULL, "Heizung", 0);
// rc = mosquitto_loop_forever(mosq,20,5); // Tried with this function but same issue.
while(run){
rc = mosquitto_loop(mosq, -1, 1);
if(run && rc){
printf("connection error!\n");
sleep(10);
mosquitto_reconnect(mosq);
}
}
mosquitto_destroy(mosq);
}
mosquitto_lib_cleanup();
return rc;
}
What I see as output is the following:
connect callback, rc=0
got message 'ON1' for topic 'Heizung'
got message for Heizung topic
got message 'ON2' for topic 'Heizung'
got message for Heizung topic
got message 'ON3' for topic 'Heizung'
got message for Heizung topic
connection error!
connect callback, rc=0
You see the connection error (where "systemctl stop mosquitto" took place). And you see reconnection appears to be successful once the broker is back again. But it does not print any of the new messages which are send by the subscriber after the broker is back. Running the mosquitto_sub command in parallel sees all messages!
Any idea what is wrong here?
Thanks a lot!
/KNEBB
Move the call to mosquitto_subscribe to the connect_callback that way it will get called on a reconnect.
Since you are connecting with the CleanSession flag set to true each time you reconnect there will be no persistent session so the broker will not know to keep the subscription.
Related
I have two simple programs: a client and a server. I'm trying to use zstr_sendfm and zstr_recv to send and receive a simple string. Roughly speaking, I'm using the code from the file transfer test in the zeromq tutorial. Here's the server function:
#define PIPELINE = 10;
int server()
{
char *name = "someName";
zctx_t *ctx = zctx_new();
void *router = zsocket_new(ctx, ZMQ_ROUTER);
zsocket_set_hwm(router, PIPELINE*2);
if (0 == zsocket_connect(router, tcp://127.0.0.1:6000))
{
printf("failed to connect to router.\n");
}
printf( "sending name %s\n, name);
zstr_sendfm( router, name );
return 0;
}
Here's the client function:
int client()
{
zctx_t *ctx = zctx_new ();
void *dealer = zsocket_new (ctx, ZMQ_DEALER);
zsocket_bind(dealer, "tcp://*:6000")
char *receivedName = zstr_recv( dealer );
printf("received the following name: %s\n", receivedName);
return 0
}
Both of these are run in two separate programs (which do nothing other than run their respective functions) on the same computer.
Here's how things always play out:
Start client function, which holds at "zstr_recv" as it's supposed to
Start server function, which connects successfully, claims to have sent the data, and exits
Client function continues to sit and wait, but claims to have not received anything from the server.
What am I missing here? I've added a bunch of error checking and even tried this out in gdb with no luck.
Help and advice appreciated.
I think you have your client and server mixed up, although in ZeroMQ client and server is not as strict as with normal sockets. Normally you would create a server with a REP socket that binds/receives/sends and a client with a REQ socket that connects/sends/receives. You should try this first and then experiment with ROUTER for the server (instead of REP) and DEALER for the client (instead of REQ).
I created a chatroom with clients and a server and everything works. But I have a problem of printing. The problem is that the client can write his message and read the message from the other clients at the same time. So I used a thread to do both at the same time. It works but look at the example what the problem is :
Here I start writing my first messHere is the received message that interrupts my writingAnd here I continue writing
I don't know if it's clear : I start writing a message but I don't send it yet because it's not over but in the same time a message is received so it prints it after the beginning of my writing message and after I can continue writing.
Do you have an idea how to fix the problem ?
Here is the client code :
void getMessage(char* message) {
size_t ln = -1;
while (ln <= 0 || ln > MESSAGE_MAX-1) {
printf(">");
fgets(message, MESSAGE_MAX, stdin);
ln = strlen(message) - 1;
}
if (message[ln] == '\n')
message[ln] = '\0';
}
void *thread_message(void *arg)
{
char* message;
message = malloc (sizeof(char) * MESSAGE_MAX);
int* sockfd = (int*)arg;
while (1) {
getMessage(message);
if (send(*sockfd, message, strlen(message), 0) == -1){
perror("Client: send message");
}
}
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
struct sockaddr_in their_addr;
// connector's address information
struct hostent *he;
char buf[MESSAGE_MAX + PSEUDO_MAX];
// ...
}
while (1) {
if ((numbytes=recv(sockfd, buf, MESSAGE_MAX+PSEUDO_MAX, 0)) == -1) {
perror("Client: recv");
return EXIT_FAILURE;
}
// ...
char* message;
message = malloc (sizeof(char) * MESSAGE_MAX);
// Here I launch the thread to write a message
pthread_t thread;
if (pthread_create(&thread, NULL, thread_message, &sockfd)) {
perror("pthread_create");
return EXIT_FAILURE;
}
}
// Here I print the messages I receive
else
{
buf[numbytes] = '\0';
printf("%s",buf);
}
}
close(sockfd);
return EXIT_SUCCESS;
}
Thanks for your help ! :)
One way to solve your problem: maybe using getch from ncurses. Save what you have already inputted into a buffer. And display messages from other clients and your input in different line of the terminal.
Note: I never used libncurses before, but when i see examples of ncurses, i know it can fulfill the need of a chat program. Hope that helps.
First, I believe that you're title doesn't match your question. You want to know about printing with threads, right? Second, try to explain in more details where each message comes from and where you got confused.
Said that, I believe that your problem is thread synchronism.
How thread works? In a really simplified way, each thread will
have a time slice to execute and then, it will give space for other
threads from your program to execute. That's why you must use mutex
to access shared variable, so threads don't use old values or
overwrite data.
But how do I print consistently? Well, you may use semaphores. Check this other stackoverflow question. Check on google for examples in C, but this post gives you the basic knowledge to work this out.
:)
I'm trying to use czmq, the first test was ok with the inproc protocol and if the "puller" and the "pusher" in the same program.
But I want to use it on different processus, I also tried ipc and tcp, and I can not achieve to make communicate the server and the client.
The server:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *reader = zsocket_new (ctx, ZMQ_PULL);
int rc = zsocket_connect (reader, "tcp://localhost:5555");
printf("wait for a message...\n");
char *message = zstr_recv (reader);
printf("Message: %s",message);
zctx_destroy (&ctx);
return 0;
}
and the client:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *writer = zsocket_new (ctx, ZMQ_PUSH);
int rc = zsocket_bind (writer, "tcp://*:5555");
assert (rc == service);
zstr_send (writer, "HELLO");
zsocket_destroy (ctx, writer);
return 0;
}
Could you tell me what is wrong with my code. I have also tried other sample codes found, but without more success.
Update
The server is waiting for messages in zstr_recv, but the messages send by the client triggers nothing on the server process.
After sending the message, the client process is destroying the socket too quickly. With inproc, you "get away with it" because inproc is fast, while TCP has to go through more hurdles before the message gets to the TCP stack.
It is true that zsocket_destroy() should block until the message is sent, if ZMQ_LINGER = -1 (the default with raw ZMQ), but the default linger for CZMQ is 0. That means dropping in-transit messages when the socket is destroyed.
Try setting the linger (with zctx_set_linger) to something bigger than zero; 10ms perhaps, but use whatever value is good for you.
I'm writing a program that's supposed to send C structures via ZeroMQ.
Therefore I'm using Google's ProtocolBuffers to serialize the structs.
I do now have the problem that my subscriber side is not receiving anything.
The Publisher prints out "Message successfully sent" so I think the Error occurs on the Subscribers side.
Publisher:
int main (void)
{
Message protomsg = MESSAGE__INIT;
void *buf;
unsigned len;
void *context = zmq_ctx_new();
void *subscriber = zmq_socket(context, ZMQ_PUB);
zmq_bind(subscriber, "ipc://my.sock");
//Initialising protomsg (not so important)
//sending message
len = message__get_packed_size(&protomsg);
buf = malloc(len);
message__pack(&protomsg, buf);
zmq_msg_t output;
zmq_msg_init_size(&output, len);
zmq_msg_init_data(&output, buf, len, NULL, NULL);
if(zmq_msg_send(&output, subscriber, 0) == -1)
perror("Error sending message \n");
else
printf("Message successfully sent \n");
zmq_msg_close(&output);
free(buf);
zmq_close (subscriber);
zmq_ctx_destroy (context);
return 0;
}
Subscriber:
int main (void){
Message *protomsg;
void *context = zmq_ctx_new ();
void *publisher = zmq_socket (context, ZMQ_SUB);
zmq_connect(publisher, "ipc://my.sock");
zmq_setsockopt(publisher, ZMQ_SUBSCRIBE, "", 0);
// Read packed message from ZMQ.
zmq_msg_t msg;
zmq_msg_init(&msg);
if(zmq_msg_recv(&msg, publisher, 0) == -1)
perror("Error receiving message \n");
else
printf("Message received");
memcpy((void *)protomsg, zmq_msg_data(&msg), zmq_msg_size(&msg));
// Unpack the message using protobuf-c.
protomsg = message__unpack(NULL, zmq_msg_size(&msg), (void *)&data);
if (protomsg == NULL)
{
fprintf(stderr, "error unpacking incoming message\n");
exit(1);
}
printf("Address: %u, Type: %u, Information[0]: %u, Information[1]: %u \n", protomsg->address-48, protomsg->frametype, protomsg->information[0], protomsg->information[1]);
zmq_msg_close (&msg);
// Free the unpacked message
message__free_unpacked(protomsg, NULL);
//close context,socket..
}
Don't know if anyone still cares about this, but here goes... I agree with #Steve-o that this is a timing issue, although I think the problem is that you are closing the publisher socket too soon.
Your publisher code publishes the message then immediately closes the socket and terminates the context. So the message exists in the publisher for milliseconds and then is gone forever.
If you run the publisher first, it does it's thing, exits and the message is gone. When you start the subscriber it attempts to connect to an IPC socket that is no longer there. ZeroMQ allows this and the subscriber will block until there is an IPC socket to connect to.
I have not reviewed the ZeroMQ IPC source code, but I suspect that, under the covers, subscriber is periodically attempting to connect to the publisher socket. Now if you run the publisher again, it might work but you have a serious race condition. If you start the publisher at the exact instant the ZeroMQ worker was attempting to retry, the connect might happen and you might even get your message before the publisher destroys everything.
I am pretty sure the problem has nothing to do with structs and protobuf. From the ZeroMQ point of view you are just sending bytes. There is no difference. If your test cases for ZeroMQ strings were truly identical with the test cases for ZeroMQ structs - then perhaps the code change added or removed a few nano-seconds that was able to break the race condition the wrong way.
Specific suggestions:
rename the socket in publisher to be "publisher" instead of subscriber (copy/paste error)
add a sleep for 30 seconds just before zmq_close (publisher);
hopefully this will fix the problem for your test code
if this does not fix it, consider switching to tcp transport and use wireshark to diagnose what is really going on.
I'm working on a C application that is suppose to talk to PostgreSQL. Right now I need to handle notices and warnings sent by the server but I'm at a loss on how to make it work.
The (very unclear) documentation says we should use PQsetNoticeReceiver to set a method as the receiver of notifications, as the default receiver just forwards the notification to PQnoticeProcessor and this prints to stderr.
I've defined a method thus
static void noticeReceiver(void *arg, const PGresult *res)
and I'm setting it as the default notice receiver on startup thus
PQsetNoticeReceiver(conn, noticeReceiver, NULL);
In my method implementation I'm simply printing some random characters to screen but it doesn't get called. Step by step debugging shows that its being set as the default notice receiver but its never called.
Any ideas?
The only way I could see it not working is if you change the connection after setting the receiver. Keep in mind that the receiver is a parameter of the connection, so if you disconnect and reconnect it would go away.
This works:
#include "libpq-fe.h"
static void myrecv(void *arg, const PGresult *res);
int main() {
PGconn *conn;
PGresult *res;
conn = PQconnectdb("");
if (PQstatus(conn) == CONNECTION_BAD)
{
printf("connection error: %s\n",
PQerrorMessage(conn));
return -1;
}
PQsetNoticeReceiver(conn, myrecv, NULL);
res = PQexec(conn, "select noisy_func();");
if (PQresultStatus(res) == PGRES_FATAL_ERROR)
printf("%s: error: %s\n",
PQresStatus(PQresultStatus(res)),
PQresultErrorMessage(res));
return 0;
}
static void
myrecv(void *arg, const PGresult *res)
{
printf("hey, got a notice saying \"%s\"\n",
PQresultErrorField(res,
PG_DIAG_MESSAGE_PRIMARY));
}