当前位置: 首页 > news >正文

在Ubuntu 18.04上,手把手教你用C语言实现MQTT收发JSON数据(附cJSON库配置)

在Ubuntu 18.04上构建C语言MQTT与JSON数据交互的完整实践指南

MQTT协议因其轻量级和高效性,已成为物联网设备通信的事实标准。而JSON作为数据交换格式,凭借其简洁性和可读性,在嵌入式系统和服务器应用中广受欢迎。本文将带领C语言开发者深入Ubuntu 18.04环境,从零开始构建一个完整的MQTT客户端,实现JSON数据的发布与订阅。

1. 环境准备与工具链配置

在开始编码之前,我们需要确保开发环境具备所有必要的工具和库。Ubuntu 18.04作为长期支持版本,提供了稳定的基础,但某些开发库需要手动安装。

首先更新系统包列表并安装基础编译工具:

sudo apt update sudo apt install build-essential cmake git wget

对于MQTT开发,我们需要Mosquitto库的两个关键组件:

  • libmosquitto-dev:MQTT客户端开发库
  • mosquitto-clients:命令行测试工具
sudo apt install libmosquitto-dev mosquitto-clients

验证Mosquitto安装是否成功:

mosquitto -v

如果系统提示命令未找到,可能需要手动添加/usr/local/lib到动态链接库路径:

echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/mosquitto.conf sudo ldconfig

2. cJSON库的集成与使用

cJSON是一个超轻量级的JSON解析器,特别适合嵌入式系统和资源受限环境。我们将采用源码集成的方式,确保项目可移植性。

首先克隆cJSON仓库到本地:

git clone https://github.com/DaveGamble/cJSON.git cd cJSON make

在项目中集成cJSON的最佳实践是将其作为静态库链接:

gcc -c cJSON.c -o cJSON.o ar rcs libcjson.a cJSON.o

然后在你的项目中包含头文件并链接静态库:

#include "cJSON.h" // 编译时添加 -L/path/to/lib -lcjson

cJSON的基本用法示例:

cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "device", "sensor-01"); cJSON_AddNumberToObject(root, "temperature", 23.5); char *json_string = cJSON_Print(root); printf("%s\n", json_string); // 释放内存 cJSON_Delete(root); free(json_string);

3. MQTT客户端实现与JSON数据封装

现在我们将实现一个完整的MQTT客户端,能够发布和订阅JSON格式的消息。首先创建基本的MQTT连接:

#include <mosquitto.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct mosquitto *mosq = NULL; void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc == 0) { printf("Connected to broker\n"); } else { fprintf(stderr, "Connect failed: %s\n", mosquitto_connack_string(rc)); } } void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { printf("Received message on topic %s: %s\n", msg->topic, (char*)msg->payload); } int init_mqtt() { mosquitto_lib_init(); mosq = mosquitto_new(NULL, true, NULL); if(!mosq) { fprintf(stderr, "Error: Out of memory.\n"); return 1; } mosquitto_connect_callback_set(mosq, on_connect); mosquitto_message_callback_set(mosq, on_message); if(mosquitto_connect(mosq, "localhost", 1883, 60) != MOSQ_ERR_SUCCESS) { fprintf(stderr, "Unable to connect to broker.\n"); return 1; } return 0; }

接下来实现JSON数据的封装与发布功能:

int publish_json_data(const char *topic, cJSON *json) { char *payload = cJSON_PrintUnformatted(json); int ret = mosquitto_publish(mosq, NULL, topic, strlen(payload), payload, 0, false); free(payload); return ret; } void subscribe_to_topic(const char *topic) { mosquitto_subscribe(mosq, NULL, topic, 0); }

4. 完整示例与常见问题排查

将上述组件整合为一个完整的示例程序,实现传感器数据的发布和订阅:

#include <unistd.h> int main() { if(init_mqtt() != 0) { return 1; } subscribe_to_topic("sensors/temperature"); while(1) { cJSON *reading = cJSON_CreateObject(); cJSON_AddStringToObject(reading, "sensor_id", "temp-001"); cJSON_AddNumberToObject(reading, "value", 22.5 + (rand() % 100) / 10.0); cJSON_AddNumberToObject(reading, "timestamp", time(NULL)); if(publish_json_data("sensors/temperature", reading) != MOSQ_ERR_SUCCESS) { fprintf(stderr, "Failed to publish message\n"); } cJSON_Delete(reading); mosquitto_loop(mosq, -1, 1); sleep(1); } mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }

编译命令示例:

gcc mqtt_json_example.c -o mqtt_json_example -lmosquitto -L. -lcjson

常见问题及解决方案:

  1. 动态链接库错误

    error while loading shared libraries: libmosquitto.so.1

    解决方案:

    sudo ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/ sudo ldconfig
  2. 头文件找不到

    fatal error: mosquitto.h: No such file or directory

    确保安装了开发包:

    sudo apt install libmosquitto-dev
  3. 端口占用

    Error: Address already in use

    查找并终止占用1883端口的进程:

    sudo lsof -i :1883 sudo kill <PID>
  4. 内存泄漏检测: 使用valgrind检查内存问题:

    valgrind --leak-check=full ./mqtt_json_example

5. 性能优化与安全实践

在实际生产环境中,我们需要考虑性能和安全性问题。以下是一些关键优化点:

连接参数优化

mosquitto_int_option(mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V311); mosquitto_int_option(mosq, MOSQ_OPT_SEND_MAXIMUM, 10); // 限制未确认消息数量

TLS加密配置

mosquitto_tls_set(mosq, "/path/to/ca.crt", NULL, "/path/to/client.crt", "/path/to/client.key", NULL); mosquitto_tls_opts_set(mosq, 1, NULL, NULL);

JSON处理优化

  • 使用cJSON_PrintUnformatted代替cJSON_Print减少传输数据量
  • 重用cJSON对象减少内存分配
  • 实现自定义的内存管理函数

MQTT QoS级别选择

QoS级别可靠性网络开销适用场景
0最低最小传感器数据
1中等中等命令和控制
2最高最大关键事务

6. 高级主题:自定义消息协议与二进制数据

虽然JSON易于使用,但在带宽受限的场景下,可以考虑更高效的二进制协议。我们可以结合MQTT和自定义编码:

#pragma pack(push, 1) typedef struct { uint32_t timestamp; uint16_t device_id; float temperature; uint8_t status; } sensor_data_t; #pragma pack(pop) void publish_binary_data(const char *topic, void *data, size_t len) { mosquitto_publish(mosq, NULL, topic, len, data, 0, false); } // 使用示例 sensor_data_t data = { .timestamp = time(NULL), .device_id = 0x1234, .temperature = 23.5f, .status = 0x01 }; publish_binary_data("sensors/binary", &data, sizeof(data));

对于需要同时支持JSON和二进制的情况,可以在MQTT主题中使用后缀区分:

  • sensors/data/json
  • sensors/data/binary

7. 系统集成与扩展思路

将MQTT客户端集成到更大的系统中时,考虑以下架构模式:

多线程模型

void *mqtt_thread(void *arg) { while(running) { mosquitto_loop(mosq, 100, 1); } return NULL; } pthread_t thread; pthread_create(&thread, NULL, mqtt_thread, NULL);

事件驱动架构

  • 使用mosquitto_loop_start创建内部线程
  • 通过回调函数处理消息
  • 与主程序通过线程安全队列通信

与数据库集成

void save_to_database(const char *json) { // 实现数据库存储逻辑 // 可以使用SQLite、MySQL等 } void on_message(...) { save_to_database((char*)msg->payload); // 其他处理逻辑 }

性能监控指标

  • 消息发布速率
  • 消息延迟
  • 内存使用情况
  • 网络带宽占用

8. 容器化部署与持续集成

为了确保应用的可移植性和易于部署,我们可以使用Docker容器:

FROM ubuntu:18.04 RUN apt update && apt install -y \ build-essential \ libmosquitto-dev \ cmake \ git WORKDIR /app COPY . . RUN git clone https://github.com/DaveGamble/cJSON.git && \ cd cJSON && \ make && \ cp libcjson.a /usr/local/lib/ && \ cp cJSON.h /usr/local/include/ RUN gcc mqtt_json_example.c -o app -lmosquitto -lcjson CMD ["./app"]

构建并运行容器:

docker build -t mqtt-json-app . docker run --network host mqtt-json-app

对于持续集成,可以配置GitHub Actions自动化测试:

name: CI on: [push] jobs: build: runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt update sudo apt install -y build-essential libmosquitto-dev cmake git - name: Build run: | git clone https://github.com/DaveGamble/cJSON.git cd cJSON make sudo cp libcjson.a /usr/local/lib/ sudo cp cJSON.h /usr/local/include/ cd .. gcc mqtt_json_example.c -o app -lmosquitto -lcjson - name: Test run: | ./app --test
http://www.jsqmd.com/news/856068/

相关文章:

  • C语言指针深度解析:从内存模型到动态分配与安全实践
  • 2026年质量好的拖拉机配套圆盘耙/轻型圆盘耙/缺口圆盘耙/液压折叠圆盘耙品牌厂家推荐 - 品牌宣传支持者
  • 2026年一体化设备的MBBR环保水处理填料/MBBR配套设备/MBBR生物填料/MBBR生物膜片公司选择指南 - 行业平台推荐
  • 别再只用串口打印了!手把手教你用J-Link RTT给STM32调试日志换个“皮肤”(含彩色日志库)
  • 别再为偶极子外露发愁了!手把手教你用Brainstorm+OpenMEEG搞定EEG源定位头模型
  • 2026年热门的天津地源热泵维保年度精选公司 - 品牌宣传支持者
  • FontForge终极指南:免费开源字体编辑器从入门到精通
  • 从XXE到RCE:手把手拆解Vulnhub靶场中那段‘天书’PHP代码的奥秘
  • 别怕伯德图!用运放搭个2型补偿器,手把手教你搞定开关电源环路稳定
  • 实测分享:搞定Buck电路振铃,手把手教你用示波器+RC缓冲电路(附参数计算Excel)
  • 告别‘+‘号拼接!JDK17文本块实战:5分钟搞定SQL、HTML多行字符串
  • 保姆级教程:用树莓派3B+VRPN,把NOKOV动捕数据喂给Pixhawk飞控
  • 玩转DevEco Studio预览器:除了看UI,Inspector和跨设备预览才是真香功能
  • 为什么92%的团队放弃Perplexity本地新闻查询?——我们用37天压力测试发现的3个致命设计盲区(含修复补丁)
  • PCL深度图像边界提取实战:区分障碍物、阴影与面纱点(避坑指南)
  • Anthropic是如何引领AI开发范式的?研究团队产品经理深度访谈
  • 竟然还在手动逐字整理工作文稿?2026年这4款AI写作工具,3分钟写完长篇职场文案
  • 手把手教你用天融信TopScanner给服务器做一次“体检”:从配置网卡到生成PDF报告
  • 安全测试新思路:用BurpSuite Turbo Intruder模拟DDoS攻击测试你的API限流机制
  • 开漏输出上拉电阻计算:从原理到I2C/GPIO实战选型
  • 告别真机折腾!用这款免费RAID模拟器在家搞定RAID 0/1/5/10配置实验
  • 炬芯ATS2835P芯片如何破解便携音箱音质、续航与体积的“不可能三角”?
  • 别再问师兄了!手把手教你从3GPP官网精准下载V2X协议(附Release版本选择指南)
  • 除了微信扫一扫,试试这款专业条码扫描APP:Scandit Barcode Scanner(附下载安装指南)
  • PLC控制柜制造:从电气设计到自动化稳定运行的完整解析
  • ARM A64指令集STXRH原子操作详解与应用
  • 下一代 Agent 架构展望:AGI 路径上的关键里程碑
  • HTML5语义化与现代Web标准
  • 你的4K电视为啥突然黑屏?可能是HDCP 2.2和1.4的Key在‘打架’
  • 告别安装冲突!Keil uVision5 同时开发51、251和ARM的保姆级配置指南