MQTT初体验-百度智能云

说明:

该文章记录了基于百度智能云MQTT服务器的测试使用过程,方便以后查阅。

MQTT协议中文版下载 https://legacy.gitbook.com/book/mcxiaoke/mqtt-cn/details

 

1、创建百度智能云

登陆入口地址:https://login.bce.baidu.com/?account=

找到如下入口并进入。

MQTT初体验-百度智能云_第1张图片

MQTT初体验-百度智能云_第2张图片

创建新项目:

MQTT初体验-百度智能云_第3张图片

设备型:百度云已提供JSON解析过滤功能,提供主题变动及发布等事件的处理。适用于一般控制类设备,不适合数据流设备。使用简单快速。

数据型:该类型设备只提供MQTT的服务器功能,不提供payload数据解析功能。使用灵活。

 

创建项目成功后会出现三个连接地址:

  1. tcp://au****.mqtt.iot.gz.baidubce.com:1883   用于TCP通讯使用
  2. ssl://au*****.mqtt.iot.gz.baidubce.com:1884  客户端MQTT.fx 使用该端口  1884支持 SSL/TLS安全认证
  3. wss://au*****.mqtt.iot.gz.baidubce.com:443

在用户列表下可进行测试,输入身份密钥执行连接,

测试主题发布与订阅时,必须保证该主题在策略列表中已添加过。只有策略列表里添加的主题才允许被使用

MQTT初体验-百度智能云_第4张图片

如上发布订阅测试通过。即可用于实际应用场合

 

2、通过 MQTT.fx 客户端测试连接

参考百度智能云提供的教程 https://cloud.baidu.com/doc/IOT/Quickstart-new.html#.E6.93.8D.E4.BD.9C.E6.AD.A5.E9.AA.A4

 

MQTT初体验-百度智能云_第5张图片

MQTT初体验-百度智能云_第6张图片

3、Socket 通讯测试

原理:MQTT C语言库提供MQTT协议序列化和反序列功能。

接收过程是将Socket接收到的数据流传递给MQTT库解算。发送工程是将要登陆信息、发布的主题、订阅主题操作序列化成数据流传递给Socket发送数据流中。完成一个数据传输的功能。MQTT是一套协议,Socket是一个数据传输工具

3.1、C语言Socket

测试使用在VS2013平台,MQTT服务器连接在Socket连接阶段完成。


#include                    
#include                   
#include                
#pragma comment (lib, "ws2_32.lib")         //socket库文件

typedef struct sockaddr_in sockaddr_in;

SOCKET s_socket;

int SocketClass::Connect(char*  hostname, int port)
{
	sockaddr_in sockaddr;
	char buffer[MAXBYTE] = { 0 };
	WSADATA wsaData;
	//加载库
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	s_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//域名解析出IP
	struct hostent *host = gethostbyname(hostname);
	char *ip;
	if (host == NULL) return -1;
	else ip = inet_ntoa(*(struct in_addr*)host->h_addr_list[0]);
	//连接服务器
	sockaddr.sin_family = PF_INET;
	sockaddr.sin_addr.S_un.S_addr = inet_addr(ip);
	sockaddr.sin_port = htons(port);
	return	connect(s_socket, (SOCKADDR*)&sockaddr, sizeof(SOCKADDR));
}

int SocketClass::Close()
{
	closesocket(s_socket);
	WSACleanup();
	return 0;
}

int SocketClass::Write(char* buff, int len)
{
	return send(s_socket, buff, len, 0);
}

int SocketClass::Read(char* buff, int len)
{
	//等待接收到数据才会退出
	return recv(s_socket, buff, len, 0);
}

3.2、MQTT登陆

int mqtt_connect(void)
{
	u8 connectBuf[CONNECTBUFMAX];
	int len;
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
	data.clientID.cstring = (char*)coco_mqttConnectName;	// 客户端标识符(自定义字符串)
	data.keepAliveInterval = 50;						// keep Alive 单位s
	data.cleansession = 0;								// 清理会话标志置位
	data.username.cstring = "aut6m7h/device";					// 用户名
	data.password.cstring = "yhnG3PJm6666666";					// 用户密码
	len = MQTTSerialize_connect(connectBuf, sizeof(connectBuf), &data);
	//发送登陆信息
	_socket.Write((char*)connectBuf, len);
	//等待登陆结果应答
	len = _socket.Read(readBuff, 512);
	if (len >= 4 && (memcmp("\x20\x02", readBuff, 2) == 0))    //参考MQTT文档CONNACK报文说明
	{
		printf_s("MQTT登陆成功\r\n");
		return 0;
	}
	else
	{
		printf_s("MQTT登陆失败\r\n");
		return -1;
	}
}

3.3、MQTT主题订阅

bool MQTT_Subscribe(char *subscribe)
{
	int len;
	int req_qos = 0;
	u8 buf[512];
	MQTTString topicString = MQTTString_initializer;
	topicString.cstring = subscribe;
	len = MQTTSerialize_subscribe(buf, sizeof(buf), 0, MQTT_packid++, 1, &topicString, &req_qos);
	_socket.Write((char*)buf, len);
	len = _socket.Read((char*)buf, 512);
	if (len >= 5 && (memcmp("\x90\x03", buf, 2) == 0))
	{
		if ((buf[4] & 0x80) != 0x80)
		{
			return true;
		}
	}
	return false;
}

3.4、MQTT主题发布

bool MQTT_Publish(char *topic, char *str)
{

	u8 fifo[512];
	int outLen = 0;
	MQTTString topicString = MQTTString_initializer;
	topicString.cstring = topic;
	int len = MQTTSerialize_publish(fifo, 512, 0, 0, 0, MQTT_packid++, topicString, (u8*)str, strlen(str));

	_socket.Write((char*)fifo, len);

	return false;
}

3.5、MQTT接收订阅消息

	int len = _socket.Read(rxfifo, 512);
	if (len >= 2)
	{
		if ((rxfifo[0] & 0xF0) == 0x30)//收到发布的消息
		{
			u8 dup;
			int qos;
			u8 retanined;
			u16 msgid;
			MQTTString receiveTopic;
			u8 *payload;
			int payloadLen;
			int ret = MQTTDeserialize_publish(&dup, &qos, &retanined, &msgid, &receiveTopic, &payload, &payloadLen, (u8*)rxfifo, len);
			if (ret)
			{
				char topic[100];
				char data[512];
				memcpy(topic, receiveTopic.lenstring.data, receiveTopic.lenstring.len);
				topic[receiveTopic.lenstring.len] = 0;

				memcpy(data, payload, payloadLen);
				data[payloadLen] = 0;
				printf_s("发序列化成功 topic[%s] payload[%s]\r\n", topic, data);
			}
		}
	}

注意:反序列化函数输出值  主题名(receiveTopic.lenstring.data)和主题的数据部分(payload)地址指向原始数据空间(rxfifo数组)中的某一个位置,结算后拷贝出来,不要对上述两个值执行写操作,以免数据破坏。

你可能感兴趣的:(MQTT,C)