说明:MQTT客户端源码种类比较多,可以根据具体需求进行选择,这里采用linux C 编程方式和HTTP方式。
Ubuntu客户端源码
地址:https://docs.emqx.io/en/broker/latest/development/resource.html
选择该源码进行下载,自行解压到linux目录,解压后目录文件如下:

直接进行make编译

编译过程提示类型不匹配,需要将include/libemqtt.h 117行修改返回值类型
修改完成后继续make,即可编译成功。
代码编写流程
//初始化mqtt,需要提供一个mqtt_broker_handle_t 链接参数结构体void mqtt_init(mqtt_broker_handle_t *broker,const char* clientid);//初始化认证信息,用户名,密码void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password);//初始化socket,内部设置一些参数和方法给broker,主机IP,端口int init_socket(mqtt_broker_handle_t* broker, const char* hostname, short port);//连接服务器,将borker对象传进去int mqtt_connect(mqtt_broker_handle_t* broker);//接收数据,参数:超时时间,返回值:接收到的数据个数int read_packet(int timeout)//发布,brocker对象,topic地址,信息,0int mqtt_publish(mqtt_broker_handle_t* broker, const char* topic, const char* msg, uint8_t retain)//订阅函数int mqtt_subscribe(mqtt_broker_handle_t* broker, const char* topic, uint16_t* message_id)
发布服务器代码
#include <libemqtt.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <arpa/inet.h>#include <linux/tcp.h>#include <signal.h>#define MAXBUF 1024int socket_id;int keepalive = 30;uint8_t read_buf[MAXBUF];int send_packet(void* socket_info, const void* buf, unsigned int count){int fd = *((int*)socket_info);return send(fd, buf, count, 0);}int init_socket(mqtt_broker_handle_t* broker, const char* hostname, short port, int keepalive){int flag = 1;// Create the socketif((socket_id = socket(PF_INET, SOCK_STREAM, 0)) < 0)return -1;// Disable Nagle Algorithmif (setsockopt(socket_id, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) < 0)return -2;struct sockaddr_in socket_address;// Create the stuff we need to connectsocket_address.sin_family = AF_INET;socket_address.sin_port = htons(port);socket_address.sin_addr.s_addr = inet_addr(hostname);// Connect the socketif((connect(socket_id, (struct sockaddr*)&socket_address, sizeof(socket_address))) < 0)return -1;// MQTT stuffsmqtt_set_alive(broker, keepalive);broker->socket_info = (void*)&socket_id;broker->send = send_packet;return 0;}int read_packet(int timeout){if(timeout > 0){fd_set readfds;struct timeval tmv;// Initialize the file descriptor setFD_ZERO (&readfds);FD_SET (socket_id, &readfds);// Initialize the timeout data structuretmv.tv_sec = timeout;tmv.tv_usec = 0;// select returns 0 if timeout, 1 if input available, -1 if errorif(select(1, &readfds, NULL, NULL, &tmv))return -2;}//定义临时变量int total_bytes = 0, bytes_rcvd, packet_length;//清理bufmemset(read_buf, 0, sizeof(read_buf));if((bytes_rcvd = recv(socket_id, (read_buf+total_bytes), MAXBUF, 0)) <= 0) {return -1;}total_bytes += bytes_rcvd; // 赋值全部长度数if (total_bytes < 2) //少于2则退出return -1;uint16_t rem_len = mqtt_parse_rem_len(read_buf); //求剩余长度uint8_t rem_len_bytes = mqtt_num_rem_len_bytes(read_buf); //求剩余长度占用字节数packet_length = rem_len + rem_len_bytes + 1; //剩余长度 + 剩余长度本身 + 固定头while(total_bytes < packet_length) // 读包,如果读到的内容和整体长度不一致则继续接收{if((bytes_rcvd = recv(socket_id, (read_buf+total_bytes), MAXBUF, 0)) <= 0)return -1;total_bytes += bytes_rcvd; // 重新赋值总长度}//返回读到的数据长度return packet_length;}int connect_mqtt_check(int packet_length,char *buf){//连接过程有返回数据,接收判断书否成功if(packet_length < 0){fprintf(stderr, "Error(%d) on read packet!\n", packet_length);return -1;}//判断是否连接MQTT的ACKif(MQTTParseMessageType(buf) != MQTT_MSG_CONNACK){fprintf(stderr, "CONNACK expected!\n");return -2;}//判断是否连接MQTT成功if(buf[3] != 0x00){fprintf(stderr, "CONNACK failed!\n");return -2;}return 0;}int main(int argc,const char *argv[]){mqtt_broker_handle_t mqtt_info;//初始化mqtt数据mqtt_init(&mqtt_info,argv[1]);//填充验证信息mqtt_init_auth(&mqtt_info,"user","admin");//创建socketinit_socket(&mqtt_info,"127.0.0.1",1883,keepalive);if(mqtt_connect(&mqtt_info) == -1){printf("mqtt_connect is fail\n");}int packet_length;//连接有返回数据,接收一下,判断是否成功packet_length = read_packet(1);if(connect_mqtt_check(packet_length,read_buf)){printf("connect mqtt server is fail \n");return -1;}char top[30];char date[20];int i;for(i=0;i<10;i++){sprintf(top,"public/test%d/topic",i);sprintf(date,"data num = %d",i);mqtt_publish(&mqtt_info,top , date, 0);usleep(500);}// mqtt_disconnect(&mqtt_info);//close_socket(&mqtt_info);return 0;}
STM32 基于LwIP - MQTT
以STM32F407x为例,首先进行网卡的基本配置:




使能FREERTOS,是为了更方便的进行使用。
代码部分:
//注意,提前修改MEMP_NUM_SYS_TIMEOUT 宏为128void StartDefaultTask(void const * argument){/* init code for LWIP */MX_LWIP_Init();/* USER CODE BEGIN StartDefaultTask */ip_addr_t ppp;uint8_t user_data;struct mqtt_connect_client_info_t cloent_info;ppp.addr = inet_addr("192.168.1.178");mqtt_client_t *client_my = mqtt_client_new();cloent_info.client_user = "admin";cloent_info.client_pass = "admin";cloent_info.keep_alive = 30;cloent_info.client_id = "STM32";mqtt_client_connect(client_my,&ppp,LWIP_IANA_PORT_MQTT,NULL,&user_data,&cloent_info);uint8_t temp[] = "hello";/* Infinite loop */for(;;){//发布mqtt_publish(client_my,"/sys/temp", (void *)&temp, sizeof(temp), 0,0,NULL, client_my);//5s发布一次数据osDelay(5000);}/* USER CODE END StartDefaultTask */}

ESP8266_RTOS_SDK
环境:ubuntu20
开发工具:IDF Python2 pip
1.环境搭建
SDK下载地:https://www.espressif.com/zh-hans/support/download/sdks-demos?keys=&field_type_tid%5B%5D=14
编译工具链下载:https://dl.espressif.com/dl/xtensa-lx106-elf-gcc8_4_0-esp-2020r3-linux-amd64.tar.gz
云盘连接:链接:https://pan.baidu.com/s/1sOaOx2mMgfvso7N80slfIQ
提取码:xkxg 
①创建一个目录(mkdir exp8266)
②安装python2及pip
sudo apt update #更新库sudo apt install python2 #安装python2sudo apt install curl #安装curl工具,方便下载其他内容sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1 #配置python2为默认python工具curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py #下载pip2包sudo python get-pip.py #安装pip
③拷贝及解压SDK、工具链

#进入ESP8266目录,执行安装依赖包
python -m pip install -r requirements.txt
git submodule add https://github.com/espressif/esp-mqtt.git components/espmqtt #获取mqtt子模块
④添加环境变量
#终端输入如下命令,并将相应代码填入其中
#pwd获取当前目录位置
mqtt@mqtt-virtual-machine:~/esp8266/ESP8266_RTOS_SDK$ pwd
/home/mqtt/esp8266/ESP8266_RTOS_SDK #这里应该与自己的路径对应,复制下来
mqtt@mqtt-virtual-machine:~/esp8266/ESP8266_RTOS_SDK$ gedit ~/.bashrc #打开后在最后一行填写

#进入到编译工具链根目录,获取路径复制
mqtt@mqtt-virtual-machine:~/esp8266/xtensa-lx106-elf/bin$ pwd


添加完成后保存退出,关闭终端重新打开,输入xt 按两下tab键看到如下画面说明成功:
⑤编译测试
#进入到SDK中
cd examples/get-started/hello_world/ #进入helloworld工程当中
make menuconfig #配置工程
⑥配置工程
⑦编译工程
make all #编译工程,等待结束
#连接开发板到虚拟机,检查ls /dev/ttyUSB0 是否存在
make flash #烧写代码,如果遇到权限问题,sudo chmod 777 /dev/ttyUSB0 即可
make monitor #打开串口监听数据
#结束监听 Ctrl + ] 即可

2.手册获取
SDK手册:https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/index.html





