Почему обратный вызов libmosquitto publish вызывается перед обратным вызовом соединения?

#mqtt #mosquitto #libmosquitto

Вопрос:

У меня есть эта программа, использующая библиотеку mosquitto MQTT:

 /*
  compile using:
  $ gcc -o libmosq libmosq.c -lmosquitto
*/
#include <stdio.h>
#include <mosquitto.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void connection_callback(struct mosquitto* mosq, void *obj, int rc)
{
  if (rc) {
    printf("connection error: %d (%s)n", rc, mosquitto_connack_string(rc));
  }
  else {
    printf("connection successn");
  }
}

void publish_callback(struct mosquitto* mosq, void *obj, int mid)
{
  printf("this is the publish callbackn");
}

int main(int argc, char *argv[])
{
  struct mosquitto *mosq = NULL;
  
  mosquitto_lib_init();
  mosq = mosquitto_new(NULL, true, NULL);
  if(!mosq) {
     fprintf(stderr, "Error: Out of memory.n");
     exit(1);
  }

  mosquitto_connect_callback_set(mosq, connection_callback);
  mosquitto_publish_callback_set(mosq, publish_callback);
  mosquitto_username_pw_set(mosq, "user1", "passwd1");
  
  int resultCode = mosquitto_connect(mosq, "localhost", 1883, 60);
  if (resultCode != MOSQ_ERR_SUCCESS) {
    fprintf(stderr, "error calling mosquitto_connectn");
    exit(1);
  }

  int loop = mosquitto_loop_start(mosq);
  if(loop != MOSQ_ERR_SUCCESS){
    fprintf(stderr, "Unable to start loop: %in", loop);
    exit(1);
  }

  char topic[] = "/testtopic";
  char msg[] = "foobar";
  int publish = mosquitto_publish(mosq, NULL, topic, (int) strlen(msg), msg, 0, false);
  if(publish != MOSQ_ERR_SUCCESS){
    fprintf(stderr, "Unable to publish: %in", publish);
    exit(1);
  }

  // hang until control C is done
  sleep(1000000);
}
 

По сути, он подключается к брокеру MQTT и публикует на нем сообщение.

Если я запущу программу, я получу следующий результат:

 this is the publish callback
connection success
 

Это означает, что обратный вызов публикации вызывается до обратного вызова соединения, что, с моей точки зрения, противоречит здравому смыслу (поскольку порядок событий противоположен: сначала происходит соединение, затем сообщение о публикации отправляется из моей программы брокеру MQTT).

Как это возможно? Почему происходит такое противоречивое поведение? Спасибо!

Комментарии:

1. Подсказка: Это публикация QOS 0….

2. Спасибо за отзыв! Если я изменю QOS на 1, я получу сообщение в обратном порядке (т. Е. Сначала connection success this is the publish callback ).

3. Однако я не уверен, что полностью понимаю, как это работает… насколько я понимаю, обратный вызов соединения вызывается при получении соединения, что эффективно подтверждает соединение. Может ли клиент MQTT публиковать сообщения еще до получения соединения?

Ответ №1:

Важно понимать, что mosquitto_connect() , хотя блокировка не блокирует весь процесс подключения, она блокируется только до тех пор, пока пакет ПОДКЛЮЧЕНИЯ не будет отправлен, она не ожидает возврата пакета ПОДКЛЮЧЕНИЯ, следовательно on_connect , обратного вызова.

Таким образом, вполне возможно, что весь код после вызова mosquitto_connect() будет выполнен вплоть до вызова на публикацию, включая вызов на публикацию, до получения этого пакета подключения. И учитывая on_publish , что обратный вызов для сообщения QOS 0 будет вызван, как только будет отправлен пакет ПУБЛИКАЦИИ (или, возможно, даже когда он будет добавлен в исходящую очередь), поскольку подтверждения нет, это также может произойти до получения СОЕДИНЕНИЯ.

Если вы хотите сделать это правильно, то весь код публикации должен быть перемещен в on_connect обратный вызов (или закрыт по флагу, установленному в этом обратном вызове).

P.S. ваша тема ДЕЙСТВИТЕЛЬНО не должна начинаться с ведущего / . Хотя технически это спецификация, она просто откладывает проблемы на потом, поскольку добавляет null запись в начало дерева тем, которая нарушит такие вещи, как общие подписки, когда вы до них доберетесь.