1.连接树莓派
配置新的树莓派请参考
刚拿到树莓派,该怎么使用(折腾)呢?_树莓派拿到后做什么-优快云博客
本人连接树莓派用的NVC可以显示图形化界面,下载VNC
链接: https://pan.baidu.com/s/1IILrcjdCIErBwDWdcv3lPg?pwd=tb63 提取码: tb63
跟着指导一步一步next即可
安装好后点击File--》new connect
(若遇到登录,点击取消即可)
点击它,输入账号密码
连接成功后即可操作树莓派可视化界面
2.在树莓派安装paho的库
因为mqtt需要用paho的库,所以要安装库
在windows下下载该文件并解压
链接: https://pan.baidu.com/s/1sTmDhjWqQrSN2A3DdgOtnw?pwd=z123 提取码: z123
因为windows不可以直接拖动文件到树莓派中,要下载WINscp软件
链接: https://pan.baidu.com/s/1EEkpGfmXh24MYEAp5flHwg?pwd=xegm 提取码: xegm
按步骤安装后,连接树莓派
连接成功后可以将解压的paho.mqtt.c-1.3.0文件复制或直接拖到树莓派桌面上
在桌面创建mqtt文件夹
在该文件夹里创建文件mqtt.c以及makefile文件
将复制过来的paho.mqtt.c-1.3.0文件放到mqtt文件夹中
进入到该文件里,右击打开终端
输入以下命令并回车进行编译
make
编译paho.mqtt.c-1.3.0若提示 openssl 错误解决方法
树莓派(Raspberry Pi)安装使用 Eclipse paho C库_树莓派 安装 matt paho c-优快云博客
之后进行安装
sudo make uninstall(去掉前面有错的安装,之前未安装可不加)
sudo make install(重新安装)
3.在树莓派编写mqtt客户端代码
mqtt.c中代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
//以下为库头文件的引入注意路径别写错
#include "./paho.mqtt.c-1.3.0/paho.mqtt.c-1.3.0/src/MQTTClient.h"
#define ALIYUN_MQTT_HOST "tcp://xxx.xxx.xxx.xxx:1883"//你的mqtt代理服务器的ip
#define ALIYUN_MQTT_CLIENT_ID ""
#define ALIYUN_MQTT_USERNAME ""
#define ALIYUN_MQTT_PASSWORD ""
#define TOPIC_S "up"//订阅话题
#define TOPIC_P "down"//发布话题
#define QOS 1
char buf[1024]={0};
void connection_lost(void *context, char *cause) {
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
int messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
printf("Message arrived\n");
strcpy(buf,message->payload);
printf("%s\n",buf);
return 1;
}
int main(int argc, char *argv[]) {
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
int rc;
MQTTClient_create(&client, ALIYUN_MQTT_HOST, ALIYUN_MQTT_CLIENT_ID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
MQTTClient_setCallbacks(client, NULL, connection_lost, messageArrived, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = ALIYUN_MQTT_USERNAME;
conn_opts.password = ALIYUN_MQTT_PASSWORD;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
MQTTClient_subscribe(client, TOPIC_S, QOS);
while (1)
{
scanf("%s",buf);
pubmsg.payload = buf;
pubmsg.payloadlen = strlen((char *)pubmsg.payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
MQTTClient_publishMessage(client, TOPIC_P, &pubmsg, &token);
MQTTClient_waitForCompletion(client, token, 10000L);
printf("Message sent\n");
}
MQTTClient_unsubscribe(client, TOPIC_S);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
makefile文件代码
#指定生成的文件名
OJB_OUT = mqtt.out
#指定每一个c文件对应的.o文件
OBJS =mqtt.o
#指定编译器
CC = gcc
#指定需要的库
ULDFLAGS = -l m -l paho-mqtt3c
###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)
$(OJB_OUT):$(OBJS)
$(CC) -o $@ $^ $(ULDFLAGS)
dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o:%.c
$(CC) -Wp,-MD,.$@.d -c $< -o $@
clean:
rm -rf .*.o.d *.o $(OJB_OUT)
之后右击mqtt文件在终端打开
输入以下命令并回车进行编译
make
之后会生成这几个文件,其中的mqtt.out即为生成的可执行文件
然后运行可执行文件即可启动mqtt客户端
./mqtt.out
4.在linux下编写mqtt转tcp的网关程序
mqtt_change.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include "MQTTClient.h"
//阿里云
#define ALIYUN_MQTT_HOST "tcp://xxx.xxx.xxx.xxx:1883"//你的mqtt代理服务器的ip
#define ALIYUN_MQTT_CLIENT_ID ""//设备id
#define ALIYUN_MQTT_USERNAME ""//用户名
#define ALIYUN_MQTT_PASSWORD ""//密码
#define TOPIC_S "down"
#define TOPIC_P "up"
#define QOS 1
char buf[1024]={0};//数据包
int flagA = 0;//标志位:MQTT收到消息为1,TCP发送后为0
int flagB = 0;//标志位:TCP收到消息为1,MQTT发送后为0
int flagC = 0;//标志位:客户端连接为0,退出为1
int acceptfd;
void connection_lost(void *context, char *cause) {
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
int messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
printf("Message arrived\n");
strcpy(buf,message->payload);
flagA = 1;
return 1;
}
//线程函数--》处理tcp的发
void * fun_tcp_send(void *arg)
{
while (1)
{
if(flagA == 1)
{
send(acceptfd, buf, strlen(buf), 0);
flagA = 0;
printf("tcp send is ok\n");
}
if(flagC == 1)
{
break;
}
}
}
//线程函数--》处理tcp的收发
void * fun_tcp(void *arg)
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("socket err");
//return;
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8887);
saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
socklen_t len = sizeof(saddr);
if (bind(sockfd, (struct sockaddr *)&saddr, len))
{
perror("bind err");
//return;
}
if (listen(sockfd, 6) < 0)
{
perror("listen err");
//return;
}
printf("listen success\n");
struct sockaddr_in aaddr;
while (1)
{
acceptfd = accept(sockfd, (struct sockaddr *)&aaddr, &len);
if (acceptfd < 0)
{
perror("accept err");
//return -1;
}
flagC = 0;
printf("accept success\n");
//来电显示:打印客户端的ip和port
printf("ip:%s port:%d\n",inet_ntoa(aaddr.sin_addr),ntohs(aaddr.sin_port));
//创建线程,发tcp的消息
pthread_t tid2;
if(pthread_create(&tid2,NULL,fun_tcp_send,NULL))
{
perror("create err");
//return;
}
//收消息
while (1)
{
//接收数据
ssize_t ret = recv(acceptfd, buf, sizeof(buf), 0);
if (ret < 0)
{
perror("recv err");
//return;
}
else if (ret == 0)
{
printf("client exit\n");
flagC = 1;
close(acceptfd);
break;
}
else
{
flagB = 1;//tcp收到消息
printf("%s\n",buf);
printf("%d\n",buf[0]);
printf("tcp recv is ok\n");
}
}
pthread_join(tid2,NULL);
}
close(sockfd);
}
int main(int argc, char *argv[]) {
//创建线程,收发tcp的消息
pthread_t tid;
if(pthread_create(&tid,NULL,fun_tcp,NULL))
{
perror("create err");
return -1;
}
//mqtt
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;//分发标记
int rc;
MQTTClient_create(&client, ALIYUN_MQTT_HOST, ALIYUN_MQTT_CLIENT_ID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
MQTTClient_setCallbacks(client, NULL, connection_lost, messageArrived, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
conn_opts.username = ALIYUN_MQTT_USERNAME;
conn_opts.password = ALIYUN_MQTT_PASSWORD;
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
//订阅主题
MQTTClient_subscribe(client, TOPIC_S, QOS);
while (1)
{
if(flagB == 1)
{
pubmsg.payload = buf;
pubmsg.payloadlen = strlen((char *)pubmsg.payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
//发布主题
MQTTClient_publishMessage(client, TOPIC_P, &pubmsg, &token);
MQTTClient_waitForCompletion(client, token, 10000L);
printf("Message sent\n");
flagB = 0;
}
}
MQTTClient_unsubscribe(client, TOPIC_S);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
pthread_join(tid,NULL);
return rc;
}
makefile
#指定生成的文件名
OJB_OUT = mqtt_change.out
#指定每一个c文件对应的.o文件
OBJS = cJSON.o mqtt_change.o
#指定编译器
CC = gcc
#指定需要的库
ULDFLAGS = -l m -l paho-mqtt3c -pthread
###########################################
#以下的内容不需要修改
###########################################
all:$(OJB_OUT)
$(OJB_OUT):$(OBJS)
$(CC) -o $@ $^ $(ULDFLAGS)
dep_files := $(foreach f,$(OBJS),.$(f).d)
dep_files := $(wildcard $(dep_files))
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o:%.c
$(CC) -Wp,-MD,.$@.d -c $< -o $@
clean:
rm -rf .*.o.d *.o $(OJB_OUT)
5.用windows下的网络调试助手模拟只能接收TCP消息的上位机
链接: https://pan.baidu.com/s/1mcjA6CK_2s67cOgv7TFZpQ?pwd=2tih 提取码: 2tih
地址为你的linux的ip--》可用ifconfig查看
端口号自己在代码中设定的8887,可以自己改
6.通信测试
运行linux下网关程序
运行树莓派下mqtt客户端
打开网络调试助手进行tcp连接
收发消息进行测试
可以看到树莓派一直在给上位机发“hello”,上位机也可以给树莓派发送“1111”
注意:本文中使用的mqtt代理服务器为阿里云服务器中配置的,具体操作请看本人的第一个文章