1. 概述


在《MQTT服务器Mosquitto 2.x编译安装配置》


https://zhuanlan.zhihu.com/p/365103802


https://blog.csdn.net/chentuo2000/article/details/115731687


一文中我们下载了最新的mosquitto源码进行了编译安装。


在下载的源码中有几个C语言的例子可以参考:



这些例子在github上也可以找到:


https://github.com/eclipse/mosquitto/tree/master/examples



下面我们看例子subscribe


2. 查看例子subscribe


  • 查看temperature_conversion目录

ls -l mosquitto-2.0.9/examples/subscribe/



  • 查看C源文件basic-1.c

cat mosquitto-2.0.9/examples/subscribe/basic-1.c


下面对注释进行了翻译。


  1. /_
  2. _ This example shows how to write a client that subscribes to a topic and does
  3. _ not do anything other than handle the messages that are received.
  4. 这个例子示范了怎样写一个客户端订阅一个主题,对收到的消息不做任何其他处理。
  5. _/
  6. #include <mosquitto.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. /_ Callback called when the client receives a CONNACK message from the broker. _/
  12. /_ 当客户端从代理接收到CONNACK消息时调用回调。 _/
  13. void on_connect(struct mosquitto _mosq, void _obj, int reason_code)
  14. {
  15. int rc;
  16. /_ Print out the connection result. mosquitto_connack_string() produces an
  17. _ appropriate string for MQTT v3.x clients, the equivalent for MQTT v5.0
  18. _ clients is mosquitto_reason_string().
  19. 打印连接结果。mosquitto_connack_string()为mqttv3.x客户端生成适当的字符串,与
  20. mqttv5.0客户端等效的是mosquitto_reason_string()。
  21. _/
  22. printf(“on_connect: %s\n”, mosquitto_connack_string(reason_code));
  23. if(reason_code != 0){
  24. /_ If the connection fails for any reason, we don’t want to keep on
  25. _ retrying in this example, so disconnect. Without this, the client
  26. _ will attempt to reconnect.
  27. 如果由于任何原因连接失败,在本例中我们不想继续重试,所以断开连接。否则,客户端将尝
  28. 试重新连接。
  29. _/
  30. mosquitto_disconnect(mosq);
  31. }
  32. /_ Making subscriptions in the on_connect() callback means that if the
  33. _ connection drops and is automatically resumed by the client, then the
  34. _ subscriptions will be recreated when the client reconnects.
  35. 在on_connect()回调中进行订阅意味着如果连接断开并由客户端自动恢复,则在客户端重新连接时将重
  36. 新创建订阅。
  37. _/
  38. rc = mosquitto_subscribe(mosq, NULL, “example/temperature”, 1);
  39. if(rc != MOSQ_ERR_SUCCESS){
  40. fprintf(stderr, “Error subscribing: %s\n”, mosquitto_strerror(rc));
  41. /_ We might as well disconnect if we were unable to subscribe _/
  42. /_ 如果无法订阅,我们应该断开连接。 _/
  43. mosquitto_disconnect(mosq);
  44. }
  45. }
  46. /_ Callback called when the broker sends a SUBACK in response to a SUBSCRIBE. _/
  47. /_ 当代理在响应订阅发送SUBACK时调用回调。 _/
  48. void on_subscribe(struct mosquitto _mosq, void _obj, int mid, int qos_count, const int _granted_qos)
  49. {
  50. int i;
  51. bool have_subscription = false;
  52. /_ In this example we only subscribe to a single topic at once, but a
  53. _ SUBSCRIBE can contain many topics at once, so this is one way to check
  54. _ them all.
  55. 在本例中,我们一次只订阅一个主题,但是订阅可以一次包含多个主题,因此这是检查所有主题的一种方
  56. 法。
  57. _/
  58. for(i=0; i<qos_count; i++){
  59. printf(“on_subscribe: %d:granted qos = %d\n”, i, granted_qos[i]);
  60. if(granted_qos[i] <= 2){
  61. have_subscription = true;
  62. }
  63. }
  64. if(have_subscription == false){
  65. /_ The broker rejected all of our subscriptions, we know we only sent
  66. _ the one SUBSCRIBE, so there is no point remaining connected.
  67. 代理拒绝了我们所有的订阅,我们知道我们只发送了一个订阅,所以没有保持连接的点。
  68. _/
  69. fprintf(stderr, “Error: All subscriptions rejected.\n”);
  70. mosquitto_disconnect(mosq);
  71. }
  72. }
  73. /_ Callback called when the client receives a message. _/
  74. /_ 当客户端收到消息时调用回调。 _/
  75. void on_message(struct mosquitto _mosq, void _obj, const struct mosquitto_message _msg)
  76. {
  77. /_ This blindly prints the payload, but the payload can be anything so take care.
  78. 这会盲目地打印有效负载,但是有效负载可以是任何东西,所以请小心。
  79. _/
  80. printf(“%s %d %s\n”, msg->topic, msg->qos, (char _)msg->payload);
  81. }
  82. int main(int argc, char *argv[])
  83. {
  84. struct <span class=”hljs-title class_“>mosquitto _mosq;
  85. int rc;
  86. /_ Required before calling other mosquitto functions _/
  87. /_ 调用其他mosquitto函数之前需要初始化 _/
  88. mosquitto_lib_init();
  89. /_ Create a new client instance.
  90. _ id = NULL -> ask the broker to generate a client id for us
  91. _ clean session = true -> the broker should remove old sessions when we connect
  92. _ obj = NULL -> we aren’t passing any of our private data for callbacks
  93. 创建新的客户端实例。
  94. id = NULL -> ask 代理为我们生成一个客户id
  95. clean session = true -> 当我们连接时,代理将删除旧会话
  96. obj = NULL -> 我们没有为回调传递任何私有数据
  97. _/
  98. mosq = mosquitto_new(NULL, true, NULL);
  99. if(mosq == NULL){
  100. fprintf(stderr, “Error: Out of memory.\n”);
  101. return 1;
  102. }
  103. /_ Configure callbacks. This should be done before connecting ideally. _/
  104. /_ 配置回调,这应该在连接之前完成。 _/
  105. mosquitto_connect_callback_set(mosq, on_connect);
  106. mosquitto_subscribe_callback_set(mosq, on_subscribe);
  107. mosquitto_message_callback_set(mosq, on_message);
  108. /_ Connect to test.mosquitto.org on port 1883, with a keepalive of 60 seconds.
  109. _ This call makes the socket connection only, it does not complete the MQTT
  110. _ CONNECT/CONNACK flow, you should use mosquitto_loop_start() or
  111. _ mosquitto_loop_forever() for processing net traffic.
  112. 将端口1883连接test.mosquitto.org,心跳时间间隔60秒。
  113. 此调用仅使套接字连接,它不完成MQTT CONNECT/CONNACK流,应该使用
  114. mosquitto_loop_star()或mosquitto_loop_forever()来处理网络流量。
  115. _/
  116. rc = mosquitto_connect(mosq, “test.mosquitto.org”, 1883, 60);
  117. if(rc != MOSQ_ERR_SUCCESS){
  118. mosquitto_destroy(mosq);
  119. fprintf(stderr, “Error: %s\n”, mosquitto_strerror(rc));
  120. return 1;
  121. }
  122. /_ Run the network loop in a blocking call. The only thing we do in this
  123. _ example is to print incoming messages, so a blocking call here is fine.
  124. _
  125. _ This call will continue forever, carrying automatic reconnections if
  126. _ necessary, until the user calls mosquitto_disconnect().
  127. 在阻塞调用中运行网络循环。在这个例子中,我们所做的唯一一件事就是打印传入的消息,所以这里的阻
  128. 塞调用是可以的。
  129. 如果需要此调用将一直持续,直到用户调用mosquitto\u disconnect()。
  130. */
  131. mosquitto_loop_forever(mosq, -1, 1);
  132. mosquitto_lib_cleanup();
  133. return 0;
  134. }



说明:


 


这个例子示范了怎样写一个客户端订阅一个主题,对收到的消息不做任何其他处理。


3. 编译例子subscribe


3.1 头文件和库文件


  • 头文件

ls -l /usr/local/include/mosquitto.h



  • 库文件

ls -l /usr/local/lib/libmosquitto.so.1



有关API的详细说明见:


https://mosquitto.org/api/files/mosquitto-h.html#mosquitto_connect



3.2 修改例子


  • 设置Username和password

在rc = mosquitto_connect(mosq, “test.mosquitto.org”, 1883, 60);


前面添加一句,用来设置Username和password:


mosquitto_username_pw_set(mosq, “ct”, “1qaz2wsx”);


  • 设置我的服务器

将rc = mosquitto_connect(mosq, “test.mosquitto.org”, 1883, 60);


中的test.mosquitto.org改成raspberrypi。


  • 编辑basic-1.c

进入例子目录:


cd mosquitto-2.0.9/examples/subscribe/



nano basic-1.c



3.3 编译


  • 编译

gcc -o basic-1 basic-1.c -lmosquitto




3.4 测试


  • 运行basic-1

./basic-1



从rc = mosquitto_subscribe(mosq, NULL, “example/temperature”, 1);可知,订阅的消息主题为example/temperature。


  • 再开一个窗口发布消息

mosquitto_pub -p 1883 -u ct -P xxxxxxxx -t example/temperature -m “26.6”



  • 订阅测试窗口收到消息


  • 用MQTT.fx远程测试

详细说明见《树莓派MQTT服务远程测试MQTT.fx


https://zhuanlan.zhihu.com/p/363373024


https://blog.csdn.net/chentuo2000/article/details/115539377



点击Publish:


订阅测试窗口收到消息