【嵌入式裸机开发】智能家居入门7:最新ONENET,MQTT协议接入,最全最新(微信小程序、MQTT协议、ONENET云平台、STM32)

智能家居入门7

    • 前言
    • 一、ONENET云平台创建产品与设备
    • 二、STM32端连接服务器前的准备
    • 三、STM32端实现
    • 四、微信小程序端连接服务器前的准备
    • 五、微信小程序端实现
    • 六、最终测试

前言

本篇文章介绍最新ONENET云平台的MQTT协议接入方法,在STM32上实现数据上云与服务器下发数据解析,以及微信小程序接入服务器。对于智能家居而言,最重要的就是通信,通信是否稳定是否响应快,这是最重要的,外设的连接与控制这些都是很简单的,网上的一搜直接就有现成的代码,所以本篇博客不会介绍关于外设的使用与控制,主要介绍最新ONENET的接入与消息解析,这个框架搭好以后,其它外设连接那都不是事儿。

硬件准备:
STM32F103C8T6
ESP8266-01S
OLED液晶显示屏或串口调试模块(USB转TTL)
DHT11(可有可无,自己虚构上传数据也可以)
烧录器


一、ONENET云平台创建产品与设备

这部分直接以视频的形式给出:

需要注意的点:
①数据协议:
这里选择的是OneJson,当然也可以选择数据流,但是它们对应的发送数据和接收数据的topic是不一样的,所以如果想省事直接使用本文代码,那就选择OneJson。
在这里插入图片描述

②新版三元组:
按照视频创建完毕后,进入设备管理的设备详情中,可以看到后续会用到的三个参数:
在这里插入图片描述


二、STM32端连接服务器前的准备

①token:
首先计算token,在连接时会用到:
在这里插入图片描述
上图中的clienid和username就是新版三元组中包含的其中两个参数:设备名称、产品ID,password就是使用官方软件计算生成的token。
接下来视频演示如何计算token:

重点提取如下:
在这里插入图片描述
纠错:上图中的时间过小,在后面多加随便一个数字既可:2810295937232。

②STM32端OneJson数据协议对应的发布、订阅topic:
在创建产品时我们选择的数据协议是OneJson,文档中有明确给出OneJson数据协议(物模型)的发布和订阅topic,如果数据协议选择数据流的小伙伴,在文档的这个界面往后翻翻就可以看到对应的。
在这里插入图片描述
在代码中,首先连接服务器,成功之后就可以订阅主题或者发布数据到主题中。
我们不止要知道发布订阅主题,对于上传数据而言还要知道上传的数据格式;对于订阅服务器下发的数据而言,还需要知道数据格式,以便于解析,下面第三点来介绍这些。

③STM32端OneJson数据协议对应的数据格式::
1、设备属性上报OneJSON数据格式:
在这里插入图片描述
图中很容易看出来数据格式中有些可以不用填,本文最终上传的数据格式如下:

{"id": "123","params": {"temp": {"value": 25.00,},"humi": {"value": 70.00,}}
}

2、设备属性设置OneJSON数据格式(服务器下发数据):
在这里插入图片描述
本文代码中订阅话题之后,若是服务器下发数据,STM32端就会收到,打印出接收到的数据如下:

 +MQTTSUBRECV:0,"$sys/bs2u21MIHC/dht11/thing/property/set",54,{"id":"208","version":"1.0","params":{"fan_ctl":true}}

代码中会对此消息进行解析,就可以将控制命令给解出来进行动作了。

④esp8266-01s烧录新的mqtt固件:
下载固件与烧录软件:通过百度网盘分享的文件:new_onenet_mqtt固件烧录.rar
链接:https://pan.baidu.com/s/1aAEqlCVyUB-9ZoaFU0qf2w?pwd=1yjb 提取码:1yjb

具体烧录过程参考:https://blog.csdn.net/jackcsdnfghdtrjy/article/details/104770612

三、STM32端实现

上传数据至服务器这部分,是参考的b站视频(彼岸有光我们有船),数据接收与解析为原创,干货来咯。
相较于之前的智能家居stm32端代码,本文的NET相关代码只剩下面两个即可:
在这里插入图片描述

esp8266.cpp:

//单片机头文件
#include "stm32f10x.h"//网络设备驱动
#include "esp8266.h"//硬件驱动
#include "delay.h"
#include "usart.h"//C库
#include <string.h>
#include <stdio.h>
#include "cJSON.h"
#include <stdlib.h>#define WIFI_SSID 						"wzqzq"								//	WIFI名
#define WIFI_PSWD 						"12345678"				//	WIFI密码#define ESP8266_WIFI_INFO			"AT+CWJAP=\"" WIFI_SSID "\",\"" WIFI_PSWD "\"\r\n"#define ESP8266_ONENET_INFO		"AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1\r\n"#define ESP8266_USERCFG_INFO  "AT+MQTTUSERCFG=0,1,\"dht11\",\"bs2u21MIHC\",\"version=2018-10-31&res=produmd5&sign=dkKx5uuWp0sMqet7BJGa2w%3D%3D\",0,0,\"\"\r\n"const char* pubtopic="$sys/bs2u21MIHC/dht11/thing/property/post";
const char* subtopic="$sys/bs2u21MIHC/dht11/thing/property/set";unsigned char esp8266_buf[ESP_RX_MAX];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;extern u8 ESP8266_INIT_OK;char bool_value[12];
char *new_json;//	函数功能:	清空缓存
void ESP8266_Clear(void)
{memset(esp8266_buf, 0, sizeof(esp8266_buf));esp8266_cnt = 0;
}//	函数功能:	等待接收完成
_Bool ESP8266_WaitRecive(void)
{if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数return REV_WAIT;if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕{esp8266_cnt = 0;							//清0接收计数return REV_OK;								//返回接收完成标志}esp8266_cntPre = esp8266_cnt;					//置为相同return REV_WAIT;								//返回接收未完成标志}//	函数功能:	发送命令
_Bool ESP8266_SendCmd(char *cmd, char *res)
{unsigned char timeOut = 200;Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));while(timeOut--){if(ESP8266_WaitRecive() == REV_OK)							//如果收到数据{if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词{ESP8266_Clear();									//清空缓存return 0;}}delay_ms(10);}return 1;}//	函数功能:	发送数据
void ESP8266_SendData(double temp,double humi,double adcx)
{char cmdBuf[512];ESP8266_Clear();								//清空接收缓存//先发送要发送数据的指令做准备sprintf(cmdBuf, "AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":%.2f\\}\\,\\\"humi\\\":{\\\"value\\\":%.2f\\}\\,\\\"ch4\\\":{\\\"value\\\":%.2f\\}}}\",0,0\r\n",pubtopic,temp,humi,adcx);		//发送命令while(ESP8266_SendCmd(cmdBuf, "OK"))delay_ms(500);memset(cmdBuf,0,sizeof(cmdBuf));delay_ms(100);
}//订阅话题
void ESP8266_sub()
{char cmdBuf[512];ESP8266_Clear();								                          //清空接收缓存sprintf(cmdBuf, "AT+MQTTSUB=0,\"%s\",0\r\n", subtopic);		//发送命令while(ESP8266_SendCmd(cmdBuf, "OK"))delay_ms(500);memset(cmdBuf,0,sizeof(cmdBuf));delay_ms(100);
}
//键值对提取
char * extract_json(const char *src) {// 找到 "params" 字段的开始位置const char *start = strstr(src, "params");DEBUG_LOG("JSON: %s\n",src);if (start) {// 跳过 "params" 字符串的长度start += strlen("params");// 找到 '{' 字符的位置,表示 params 对象的开始while (*start && *start != '{') {start++;}if (*start == '{') {// 从 '{' 开始复制,直到 '}' 或字符串结束const char *end = strchr((char *)start, '}');if (end) {// 计算需要复制的长度size_t len = (size_t)(end - start);// 创建一个新的缓冲区并复制目标字符串char *new_json = (char *)malloc(len + 2); // +1 为了空字符,+1 为了避免潜在的 '{'if (new_json) {strncpy(new_json, start, len);new_json[len] = '}'; // 添加 '}' 以确保 JSON 结束new_json[len + 1] = '\0'; // 确保以空字符结尾DEBUG_LOG("Extracted JSON: %s\n",new_json);return new_json;}}}}
}//解析
void parse_onenet_command(const char *json_str) {cJSON *json, *led_ctl_item, *fan_ctl_item;char* temp = extract_json(json_str);json = cJSON_Parse(temp);if (json == NULL) {// 处理 JSON 解析错误const char *error_ptr = cJSON_GetErrorPtr();printf("Error parsing JSON: %s\n", error_ptr);return;}// 直接获取 "led_ctl" 的值led_ctl_item = cJSON_GetObjectItem(json, "led_ctl");if (led_ctl_item != NULL){if(led_ctl_item -> valueint){DEBUG_LOG("led open\n");}else{DEBUG_LOG("led close\n");}} fan_ctl_item = cJSON_GetObjectItem(json, "fan_ctl");if (fan_ctl_item != NULL){if(fan_ctl_item -> valueint){DEBUG_LOG("fan open\n");}else{DEBUG_LOG("fan close\n");}}// 清理并释放内存free(new_json);free(temp);cJSON_Delete(json);
}//主函数或者定时器中循环调用,如果esp8266接收到数据,就解析
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{char *ptrIPD = NULL;do{if(ESP8266_WaitRecive() == REV_OK)								//如果接收完成{parse_onenet_command((const char *)esp8266_buf);}delay_ms(5);timeOut--;	//延时等待} while(timeOut > 0);return NULL;														//超时还未找到,返回空指针}//	函数功能:	初始化ESP8266
void ESP8266_Init(void)
{ESP8266_Clear();DEBUG_LOG("0. AT - 测试MCU-8266通讯");while(ESP8266_SendCmd("AT\r\n", "OK"))delay_ms(500);DEBUG_LOG("1. AT+RST - 软复位8266");ESP8266_SendCmd("AT+RST\r\n", "");delay_ms(500);ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");delay_ms(500);DEBUG_LOG("2. AT+CWMODE=1,1 - 设置8266工作模式为STA");while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))delay_ms(500);DEBUG_LOG("3. AT+CWDHCP=1,1 - 使能STA模式下DHCP");while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))delay_ms(500);DEBUG_LOG("4. AT+CWJAP - 连接WIFI -> [ SSID: %s ]  -> [ Password: %s ] ",WIFI_SSID, WIFI_PSWD);while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))delay_ms(500);DEBUG_LOG("6. AT+MQTTUSERCFG=0,1 - 设置user信息:ID,devicename,token");while(ESP8266_SendCmd(ESP8266_USERCFG_INFO, "OK"))delay_ms(500);DEBUG_LOG("7. AT+MQTTCONN=0 - 连接服务器:ip,端口号");while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "OK"))delay_ms(500);DEBUG_LOG("服务器已连接");
}//	函数功能:	串口2收发中断
void USART2_IRQHandler(void)
{if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断{if(esp8266_cnt >= sizeof(esp8266_buf))	esp8266_cnt = 0; //防止串口被刷爆esp8266_buf[esp8266_cnt++] = USART2->DR;USART_ClearFlag(USART2, USART_FLAG_RXNE);}}

集成到自己的代码时需要修改wifi、产品ID、设备名称、token、发布订阅话题、发送数据中的标识符要与自己在云平台创建的一致。重要代码的注释也写的很清楚了,结合上面讲的那些话题与数据格式,很容易就可以看懂。
这部分代码解决之后就可以使用云平台进行测试了,测试过程如下视频:

四、微信小程序端连接服务器前的准备

跟第二节一样,也需要准备token,前面已经弄好了,直接复制即可。

①onenet 云端API介绍:
通过阅读onenet物联网开放平台的文档,发现OneNET API提供产品、设备、服务等云端API,使用标准HTTP方法实现资源CURD操作,其中URL中的中文参数使用UTF-8编码。具体的大家可以去看文档,写的很清楚,所以微信小程序使用这种方式接入服务器。
在这里插入图片描述
从文档中的接口列表可以看到物模型使用的接口:
在这里插入图片描述

②具体的使用方式如下:
1、设备属性最新数据查询(微信小程序从服务器获取数据):
在这里插入图片描述
文档往下翻可以看到使用示例,微信小程序中参考这种格式即可:
在这里插入图片描述
2、设备属性期望设置(微信小程序发布数据到图中所示的接口地址,此时服务器对应的就会将此数据发布到:$sys/{pid}/{device-name}/thing/property/set这个话题中,这个话题也就是stm32端订阅的话题,这样32端就会接收到微信小程序下发的指令):
在这里插入图片描述
文档往下翻可以看到使用示例,微信小程序中参考这种格式即可:
在这里插入图片描述
有了上面这两个示例,就可以在微信小程序中进行代码的编写了!

五、微信小程序端实现

index.js

Page({data: {temp:0.0,humi:0.0,gas_ch4:0.0,fumes:0.0,leds:false,fen:false,water:false},/* 获取OneNET云平台设备数据 */getinfo() {/* 发起 HTTPS 网络请求 获取设备参数 */wx.request({/* 网址、产品ID、设备名 */url: "https://iot-api.heclouds.com/thingmodel/query-device-property?product_id=bs2u21MIHC&device_name=dht11",header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},method: "GET",   /* HTTP 请求方法:获取 */success: res => {console.log("获取成功", res)this.setData({humi: res.data.data[3].value,temp: res.data.data[5].value,gas_ch4: res.data.data[0].value,})}});},//下发指令:ledonledsChange(event){const that = thisconsole.log(event.detail.value);const sw = event.detail.valuethat.setData({leds:sw})if(sw){wx.request({url: 'https://iot-api.heclouds.com/thingmodel/set-device-property',method: 'POST',header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},data: {"product_id": "bs2u21MIHC","device_name": "dht11","params": {"led_ctl": true   /* 控制板端LED */}},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})}else{wx.request({url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',method: 'POST',header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},data: {"product_id": "bs2u21MIHC","device_name": "dht11","params": {"led_ctl": false   /* 控制板端LED */}},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})}},//下发指令:风扇onfenChange(event){const that = thisconsole.log(event.detail.value);const sw = event.detail.valuethat.setData({fen:sw})if(sw){wx.request({url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',method: 'POST',header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},data: {"product_id": "bs2u21MIHC","device_name": "dht11","params": {"fan_ctl": true   /* 控制板端空调 */}},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})}else{wx.request({url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',method: 'POST',header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},data: {"product_id": "bs2u21MIHC","device_name": "dht11","params": {"fan_ctl": false   /* 控制板端空调 */}},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})}
},sliderChanging:function(e){console.log(e.detail.value)wx.request({url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',method: 'POST',header: {/* 用户鉴权信息 */"authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"},data: {"product_id": "bs2u21MIHC","device_name": "dht11","params": {"curtain": e.detail.value   /* 控制板端窗帘,这个例子中stm32端没写 */}},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})},onLoad() {var that = thissetInterval(function(){that.getinfo()},5000)}})

上面的代码也不是完整的,有了思路和格式就是非常大的帮助,大家可以参照这样的发布与请求数据的格式将代码集成到自己的项目中,进行自己的界面设计,注意替换产品ID、设备名称、鉴权信息(token)等。

六、最终测试

微信小程序代码也调试好之后,就可以进行联调了,开发板上电连接上服务器中,微信小程序观察能否接收到数据,并测试能否下发指令控制开发板,具体如下视频:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/406902.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TCP和UDP编程的学习

UDP编程特点&#xff1a;c/s模型 不可靠 &#xff1b; 无链接 &#xff1b;数据报形式&#xff08;效率高&#xff09;&#xff1b; TCP编程特点&#xff1a; 面向链接&#xff1b; 可靠传输&#xff1b;&#xff08;保证数据准确可靠&#xff09;&#xff1b; 面向字节流&a…

基于x86 平台opencv的图像采集和seetaface6的口罩人脸检测识别功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.2 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的口罩人脸检测识别功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的口罩人脸检测…

【blender】一个汉堡包

第一次建模&#xff0c;哈哈汉堡包样式大差不差。至于这么做的&#xff0c;那么多快捷键完蛋&#xff0c;忘得差不多了&#xff01; 官网地址&#xff1a;https://www.blender.org/download/ 我下载的是4.2版本

DHCP协议-CSP认证

文章目录 DHCP协议 DHCP协议 stringstream的用法 应用实践 #include<bits/stdc.h>using namespace std;signed main() {string s"wo shi wwl, also wlw";stringstream ss;ss<<s;while(ss>>s){if(s[s.size()-1],) s[s.size()-1] ;cout<<s<…

Excel的使用总结2

目录 1、数据的分割 2、根据某个条件筛选出来的数据&#xff0c;想要直接复制&#xff0c;并粘贴到与筛选数据对应的位置 3、几个单元格中的内容连接 4、如果一个表格数据很多&#xff0c;但是你想查看一列中是否有数据&#xff0c;如何查看 1、数据的分割 首先&#xff0c…

SwapPrompt(论文解读): Test-Time Prompt Adaptation for Vision-Language Models

2023(Neural IPS) 摘要 测试自适应 &#xff08;TTA&#xff09; 是无监督域自适应&#xff08;UDA&#xff09;中一种特殊且实用的设置&#xff0c;它允许源域中的预训练模型去适应另一个目标域中的未标记测试数据。为了避免计算密集型的骨干网络微调过程&#xff0c;因此利…

JavaScript(31)——内置构造函数

构造函数 构造函数是一种特殊的函数&#xff0c;主要用于快速初始化对象 用大写字母开头只能由new操作符来执行 function Stu(name, age) {this.name namethis.age age}const xiaom new Stu(小明, 18)const xiaoh new Stu(小红, 19)console.log(xiaom);console.log(xiaoh…

使用 Visual Studio 编辑器作为 DailyNotes 的 markdown 编辑器

DailyNotes 是我使用过的最优秀的日常笔记管理工具&#xff0c;为它配置一个好的 markdown 编辑器&#xff0c;可以大幅提升效率。 除了使用 Typora 作为 markdown 编辑器&#xff0c;Visual Studio Code 也是一个非常不错的选择&#xff0c;令人惊喜的是&#xff0c;它也支持…

ts枚举类型校验,提示枚举信息

ts 类型验证&#xff0c;提示枚举信息 const eventTypeList [MOUSE_MOVE, // 鼠标移动LEFT_CLICK // 左键单击// MOUSE_OUT, ] as consttype EventTypeList typeof eventTypeList[number]

Pod基础使用

POD基本操作 1.Pod生命周期 在Kubernetes中&#xff0c;Pod的生命周期经历了几个重要的阶段。下面是Pod生命周期的详细介绍&#xff1a; Pending&#xff08;待处理&#xff09;: 调度: Pod被创建后&#xff0c;首先进入“Pending”状态。此时&#xff0c;Kubernetes的调度器…

uniapp中 使用 VUE3 组合式API 怎么接收上一个页面传递的参数

项目是uniapp &#xff0c;使用了vue3 vite // 使用的组合式API 的 语法糖 <script setup> // 无法使用 onLoad <script> 使用不了下面方法获得上一个页面参数传递 onLoad(options){ } 解决方案1&#xff08;亲测Ok&#xff09;&#xff1a;消息通知与监听…

虹软科技25届校招笔试算法 A卷

目录 1. 第一题2. 第二题3. 论述题 ⏰ 时间&#xff1a;2024/08/18 &#x1f504; 输入输出&#xff1a;ACM格式 ⏳ 时长&#xff1a;2h 本试卷分为不定项选择&#xff0c;编程题&#xff0c;必做论述题和选做论述题&#xff0c;这里只展示编程题和必做论述题&#xff0c;一共三…

Win11搭建Angular开发环境

作为一名后端程序员&#xff0c;无论当前的工作是否需要&#xff0c;会一点点前端无疑对自己是有帮助的。今天就来介绍一下如何搭建Angular的开发环境。我也是摸着石头过河&#xff0c;所以很多东西也不熟悉&#xff0c;先按照Angular官网的介绍来配置吧。 这个是Angular最新版…

mmyolo训练模型报错:ValueError: Key img_path is not in available keys解决办法

使用mmyolo训练模型 的时候报错&#xff1a;ValueError: Key img_path is not in available keys. Traceback (most recent call last): File “tools/train.py”, line 123, in main() File “tools/train.py”, line 119, in main runner.train() File “/root/anaconda3/en…

erlang学习:erlang学习:书上案例22.6练习题3

初步实现了书上案例第二&#xff0c;三问的要求&#xff0c;对输出结果有部分偏差&#xff0c;没有实现对已完成任务状态的记录&#xff0c;因此已完成任务输出无论如何都是0&#xff0c;明天会在record中加一个字段进行已完成任务状态的记录 (2) 添加一个名为job_centre:stati…

服务器备份

服务器备份 一、方案 FreeFileSync freeSSHd Windows任务计划程序 FreeFileSync&#xff1a;设置文件备份方案&#xff08;双向同步、镜像同步、更新同步、自定义同步&#xff09;&#xff0c;适用于本地的文件同步之外&#xff0c;还支持 Google Driver、SFTP 和 FTP 三种…

泛微基于华为仓颉编程语言开发公文交换系统 推动办公软件全面国产化

2024年6月21日下午&#xff0c;华为终端BG软件部总裁龚体先生在华为开发者大会主题演讲《鸿蒙原生应用&#xff0c;全新出发&#xff01;》中向全球开发者介绍了华为自研仓颉编程语言&#xff0c;并发布了HarmonyOS NEXT仓颉语言开发者预览版。这是华为首次公开发布仓颉编程语言…

Windows—UDP编程

Client骨架&#xff1a; #include <iostream> #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib")int main() {//启动Winsock DLLWORD wVersionRequested MAKEWORD(2, 2);WSADATA lpWSAData;WSAStartup(wVersionRequested, &lpWSAData);//…

实现AOP机制 + Spring总结

文章目录 1.目录2.SmartAnimal.java 接口&#xff08;JDK代理必须有接口&#xff09;3.SmartDog.java4.SmartAnimalAspect.java5.SunSpringApplicationContext.java1.在Bean的后置处理器之后使用动态代理2.完整代码 6.测试1.AppMain.java 调用被代理的类的方法2.结果 7.Spring底…

Unity抖音直播玩法开发流程

前言 近两年直播玩法逐渐新兴起来了&#xff0c;也出现不少质量还不错的作品&#xff0c;比如下列《红蓝对决》《三国全战》等。近期我们也做了一款直播玩法&#xff0c;就此记录下开发流程。 1&#xff0c;申请应用 进入抖音开发者平台&#xff0c;在首页入驻平台。 如果是…