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

UNIAPP微信小程序中使用Base64编解码原理分析和算法实现


为何要加上UNIAPP及微信小程序,可能是想让检索的翻围更广把。😇 Base64的JS原生编解码在uni的JS引擎中并不能直接使用,因此需要手写一个原生的Base64编解码器。正好项目中遇到此问题,需要通过URLLink进行小程序跳转并携带Base64参数进行数据传递,从而更好的在跳转后的初始化中进行鉴权等其他操作。特此将Base64的相关内容进行分析。需要具体实现算法的直接跳到最后即可

Base64分析

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符 来表示二进制数据的方法。简单来说就是一种编码的格式。为了更方便的进行数据传递。为什么不直接用ascii编码传递,可见后续ascii编码表的一堆其他符号,由于不同的设备对字符处理的方式有一些不同,所以用纯文本格式是最安全且高效的,因此base64的作用用于将非文本数据转换为可安全传输的文本格式,如果你希望你要发送的东西最后能完整的呈现的话,这是非常好的编解码方案。同理还有Base16 32 等,掌握其算法,可以根据业务需求自己编写编解码器并指定编码表。

为何要编码呢?我直接传递不行么?

首先这个问题很好回答,如果你的场景支持你预想的方式进行传递,那你完全可以不用Base64进行数据传递,而是采用更方便的JSON或其他传输格式。总的来说Base64并没有什么好神奇的,不过是一个不同载体之间的传递方案罢了,例如URL中拼接URL就需要对拼接的URL进行URL编码,例如需要结构化描述性强的数据传输,则用XML格式。(解决问题的方案很多种,并非一定是用某种方案,而经验更丰富的人会明白不同的方案间带来的长期维护以及后续迭代的方便性以及后续业务的拓展约束性)

有哪些场景可以使用Base64?
例如网站证书的编码,电子邮件的附件传递,再比如要传输 XML 格式文件,其中内嵌一段 XML 格式代码,那此时标签会造成混淆,因此可以将内嵌的 XML 进行Base64编码,接收方再通过解码拿到关键数据。还有网页中的小icon或小图片等,可以利用Base64进行直接内嵌,减少网络请求。也有可能是你要传输一段纯文本的格式数据,但是你想在其中内嵌一张图片,那么你可以在数据中嵌入Base64编码的图片字符。






ASCII编码

如果你是计科的,那你一定听过ASCII码,这是一个历史悠久的字符编码格式,如果是非科班,你可能又有疑问?整这么多码干啥?

首先需要明白计算机内部进行存储数据的最基本单位是 Bit 也就是 0 或者 1的二进制数字,在最初的编码员操作的时候,都是手敲这些玩意,你比如要表示 666,就是1010011010。就这二进制,你除非背过不然也一时半会看不出来,得通过运算得出表示的是 666 。那更别说字符了。

更早之前都没有操作系统这回事的时候,基本都是输入输出系统,用于军事科学或高级复杂计算,那会儿每个厂商比如IBM、DEC等自己都涉及了一套编码的方案,用于表示字符,那这样的话其实兼容性就十分的不好,不同厂商之间的电脑数据传输也需要进行不同的编解码。后来就美国国家标准协会发布了一套统一的编码格式,就叫ASCII码(如下图),虽然是美国发布的,但起技术的前沿发展性,几乎全球都认可并使用。后续的Base64编码也需要用到ASCII编码表

在这里插入图片描述


好了相信你已经知道了这些码的作用,其实是必要的,否则无法进行数据的直观展示,因为目前计算机是普及的,人们希望直观的看到数据,现在ASCII也是过去式了,主流是Unicode,Unicode 提供了超过 140000 个字符的编码空间,也叫万国码,涵盖了世界上几乎所有的语言字符,是一种跨平台跨国家的乱码解决方案。然后unicode仅是一个编码的方案,并没有规定具体的编码方式(直接按照unicode硬存也行,只是没有算法的加持效率非常低),所以UTF-8出现了。具有变长编码的算法,能够大幅度节省存储的空间,也能确保数据转换的覆盖性,还有就是完美向下兼容ASCII,所以说UTF-8是unicode这种编码集的最终的优化实现。






Base64原理分析

相信你已经了解编码这回事了,接下来直接上图,计算机的底层虽然是2进制组成,但展示的时候通常是10进制的
在这里插入图片描述


例如我现在需要将 “Base64” 这个字符串进行 Base64编码,简单来说就是将字符的二进制转为Base64编码,将字符转为二进制的过程又需要依赖ASCII编码,具体实现步骤如下


1、首先拆分一下,得到如下6个字符

在这里插入图片描述


2、此时按照将字符进行二进制的转换(此时用到了ASCII编码)

在这里插入图片描述


3、将二进制进行拼接串联
在这里插入图片描述


4、按照 6 位为单位进行分组

在这里插入图片描述


5、将分组的二进制转10进制
在这里插入图片描述


6、用10进制对照Base64编码表进行取值
在这里插入图片描述

base64编码总结:字符 → 转十进制 → 转二进制 → 以6位分组组成新的二进制组 → 十进制 → 转base64表字符


浏览器Base64编码结果对照:
在这里插入图片描述

至此已经实现Base64的编码流程推理,且得到了验证,同理进行解码的逻辑则相反,这里有一个点需要注意,就是最终的base64编码的长度需要是4的倍数,如果不是就要在结尾用 = 补齐,这里的逻辑可以用HelloWorld去进行编码尝试最终的结果为 SGVsbG9Xb3JsZA==

在这里插入图片描述





Base64 算法实现

首先需要实现的就是Base64编解码的定义,所以这里先定义一个常量用来存储base64的编码表,索引就是其value,这里合计65个字符,是因为把后续编码不足4位需要补 = 的情况也考虑进来,直接放到编码表中,方便后续处理。

// Base64编码表
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';// Base64编码
export function encode(str) {console.log(str);
}// Base64解码
export function decode(str) {}


Base64编码

处理最佳理想情况,输入字符为3个,转为4个整的base64字符

// Base64编码
export function encode(str) {let result = ''// 循环遍历字符串,每次处理3个字符// 一个字符对应一个ASCII,一个ASCII对应8bit,总24bit,即3byte,一个base64为6bit// 因此3个输入字符为一组正好能转为4个base64字符 --> 3byte * 8 = 6bit * 4for (let i = 0; i < str.length; i += 3) {// 分别计算每个字符对应的base64编码值let char1 = str.charCodeAt(i) >> 2;		// 取byte1前6位let char2 = (str.charCodeAt(i) & 3) << 4 | str.charCodeAt(i + 1) >> 4;	// 取byte1后2位+byte2前4位let char3 = (str.charCodeAt(i + 1) & 15) << 2 | str.charCodeAt(i + 2) >> 6;	// 取byte2后4位+byte3前2位let char4 = str.charCodeAt(i + 2) & 63; // 取byte3的后6位}
}

这是非异常情况,进行编码的字符的二进制位数正好是能被6整除的情况,如果最终转换不足6位的话,按照base64的编码规则需要在后面加 = 号进行填充,以确保编码后的长度是4的倍数

具体来说,如果原始数据的字节数为1个字节,那么对应的Base64编码结果会有2个填充字符“=”;如果原始数据的字节数为2个字节,那么对应的Base64编码结果会有1个填充字符“=”。举例如下:

在这里插入图片描述

如果按照 abc 3个字符为1组 进行转码, 将得到 3 * 8 bit,将正好转换为 4 * 6的base64编码,也就是3个输入字符对应了4个base64编码字符,这也是为什么说经过base64编码后的数据长度会比之前多出1/3。因此,无论原始数据的长度如何,Base64编码后的结果字符串长度都会是4的倍数。


处理非理想情况

// Base64编码
export function encode(str) {let result = ''// 循环遍历字符串,每次处理3个字符// 一个字符对应一个ASCII,一个ASCII对应8bit,总24bit,即3byte,一个base64为6bit// 因此3个输入字符为一组正好能转为4个base64字符 --> 3byte * 8 = 6bit * 4for (let i = 0; i < str.length; i += 3) {// 分别计算每个字符对应的base64编码值let char1 = str.charCodeAt(i) >> 2; // 取byte1前6位let char2 = (str.charCodeAt(i) & 3) << 4 | str.charCodeAt(i + 1) >> 4; // 取byte1后2位+byte2前4位let char3 = (str.charCodeAt(i + 1) & 15) << 2 | str.charCodeAt(i + 2) >> 6; // 取byte2后4位+byte3前2位let char4 = str.charCodeAt(i + 2) & 63; // 取byte3的后6位// 判断是否需要填充(每次共处理3个输入字符,只需要判断是否存在第二与第三个字符)// 一个输入字符 8 bit,最起码会产生 2个 base64字符if (isNaN(str.charCodeAt(i + 1))) {char3 = char4 = 64; // 第二个字符不存在时,填充末尾2个 =} else if (isNaN(str.charCodeAt(i + 2))) {char4 = 64 // 第三个字符不存在时,填充末尾1个 = }
}

将转码的10进制数进行查表换取对应字符并返回

// Base64编码
export function encode(str) {let result = ''// 循环遍历字符串,每次处理3个字符// 一个字符对应一个ASCII,一个ASCII对应8bit,总24bit,即3byte,一个base64为6bit// 因此3个输入字符为一组正好能转为4个base64字符 --> 3byte * 8 = 6bit * 4for (let i = 0; i < str.length; i += 3) {// 分别计算每个字符对应的base64编码值let char1 = str.charCodeAt(i) >> 2; // 取byte1前6位let char2 = (str.charCodeAt(i) & 3) << 4 | str.charCodeAt(i + 1) >> 4; // 取byte1后2位+byte2前4位let char3 = (str.charCodeAt(i + 1) & 15) << 2 | str.charCodeAt(i + 2) >> 6; // 取byte2后4位+byte3前2位let char4 = str.charCodeAt(i + 2) & 63; // 取byte3的后6位// 判断是否需要填充(每次共处理3个输入字符,只需要判断是否存在第二与第三个字符)// 一个输入字符 8 bit,最起码会产生 2个 base64字符if (isNaN(str.charCodeAt(i + 1))) {char3 = char4 = 64; // 第二个字符不存在时,填充末尾2个 =} else if (isNaN(str.charCodeAt(i + 2))) {char4 = 64 // 第三个字符不存在时,填充末尾1个 = }result += base64Table.charAt(char1) + base64Table.charAt(char2) + base64Table.charAt(char3) + base64Table.charAt(char4)}return result;
}

PS:
在编码的算法中,我使用的是 charCodeAt() 取获取该字符对应的Unicode 编码值,也就是对应的10进制,在推理图解的过程中,使用的是ASCII做举例。ASCII属于Unicode的子集,在JS中可以利用 charCodeAt()拿到对应的10进制数


测试:
加粗样式

在这里插入图片描述

可以在实现编码算法后,进行aababc的编码算法推理过程,将更好的了解其逻辑

在这里插入图片描述

对于输入字符 a 的情况,进行 str.charCodeAt(i + 1) 时候会出现 NaN ,此时再进行移位操作, NaN会转为0,因此不会引发异常,在获取不到的情况下都会转为 00000000,按位与 00010000 时,即为16,对应base64表为 Q,后位字符都为NaN即为 = ,则最终结果为 YQ==





Base64解码

经过base64的编码过程,解码就好处理多了,同理还是利用位计算还原逆推base64编码,将其对表进行转换

先处理异常字符情况

// Base64解码
export function decode(str) {let result = '';let value1, value2, value3, value4; // 存储4个base64字符所对应的索引let char1, char2, char3; // 存储解码后的3个原始字符// 处理字符串中异常字符,仅保留base64字符str = str.replace(/[^A-Za-z0-9+/=]/g, '')return result;
}

借着按照4个字符一组取出base64的字符,并且取出对应value

// Base64解码
export function decode(str) {let result = '';let value1, value2, value3, value4; // 存储4个base64字符所对应的索引let char1, char2, char3; // 存储解码后的3个原始字符// 处理字符串中异常字符,仅保留base64字符str = str.replace(/[^A-Za-z0-9+/=]/g, '')for (let i = 0; i < str.length; i += 4) {// 从base64编码表中获取字符所对应的valuevalue1 = base64Table.indexOf(str.charAt(i));value2 = base64Table.indexOf(str.charAt(i + 1));value3 = base64Table.indexOf(str.charAt(i + 2));value4 = base64Table.indexOf(str.charAt(i + 3));}}

将4个base字符解码成3个原始字符

// Base64解码
export function decode(str) {let result = '';let value1, value2, value3, value4; // 存储4个base64字符所对应的索引let char1, char2, char3; // 存储解码后的3个原始字符// 处理字符串中异常字符,仅保留base64字符str = str.replace(/[^A-Za-z0-9+/=]/g, '')for (let i = 0; i < str.length; i += 4) {// 从base64编码表中获取字符所对应的valuevalue1 = base64Table.indexOf(str.charAt(i));value2 = base64Table.indexOf(str.charAt(i + 1));value3 = base64Table.indexOf(str.charAt(i + 2));value4 = base64Table.indexOf(str.charAt(i + 3));// 将4个base64字符解码成3个原始字符char1 = value1 << 2 | value2 >> 4;char2 = (value2 & 15) << 4 | value3 >> 2;char3 = (value3 & 3) << 6 | value4;// 这样会有bug// char1 = value1 << 2 | value2 >> 4;// char2 = value2 << 4 | value3 >> 2;// char3 = value3 << 6 | value4;}
}

需要注意的是,JavaScript 在 1995 年诞生的时候,Unicode 已经发布。因此 JavaScript 的作者 Brendan Eich 在设计之初就使用 Unicode 作为 JavaScript 的唯一编码方式。我们知道 Unicode 是一个字符集,具体的编码方式有 UTF-8,UTF-16,UTF-32 等等。 JavaScript 语言采用 Unicode 字符集,但是只支持一种编码方法,就是UTF-16。因此这样进行位运算之前,必须清空高位,不然进行左移时,高位会进位,并不会按照ASCII的8 bit 作为一个字符舍弃高位。虽然base64进行转换的时候是只有英文字符加数字等这种简单情况,但是进行转码的是JS的引擎所以需要注意这个问题。

举例:
如果将base64字符W进行解码时就有这个问题的出现,W对应的value是22,分析过程如下

在这里插入图片描述

在这里插入图片描述
可以发现这里是会进位的


最后进行解码字符拼接,这里同理需要考虑 = 的情况,如果是 = 则是补位,无需拼接

// Base64解码
export function decode(str) {let result = '';let value1, value2, value3, value4; // 存储4个base64字符所对应的索引let char1, char2, char3; // 存储解码后的3个原始字符// 处理字符串中异常字符,仅保留base64字符str = str.replace(/[^A-Za-z0-9+/=]/g, '')for (let i = 0; i < str.length; i += 4) {// 从base64编码表中获取字符所对应的valuevalue1 = base64Table.indexOf(str.charAt(i));value2 = base64Table.indexOf(str.charAt(i + 1));value3 = base64Table.indexOf(str.charAt(i + 2));value4 = base64Table.indexOf(str.charAt(i + 3));// 将4个base64字符解码成3个原始字符char1 = value1 << 2 | value2 >> 4;char2 = (value2 & 15) << 4 | value3 >> 2;char3 = (value3 & 3) << 6 | value4;// 解码后字符拼接(最少会有一个字符[依赖value1和value2])result += String.fromCharCode(char1);if (value3 !== 64) result += String.fromCharCode(char2);if (value4 !== 64) result += String.fromCharCode(char3);}return result;
}

以上就是最终实现了,下面开始测试

JS情况:

在这里插入图片描述

自写算法情况:

编码:
在这里插入图片描述

解码:
在这里插入图片描述

全字符编解码:
在这里插入图片描述

完整算法代码

// Base64编码表
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';// Base64编码
export function encode(str) {let result = '';// 循环遍历字符串,每次处理3个字符// 一个字符对应一个ASCII,一个ASCII对应8bit,总24bit,即3byte,一个base64为6bit// 因此3个输入字符为一组正好能转为4个base64字符 --> 3byte * 8 = 6bit * 4for (let i = 0; i < str.length; i += 3) {// 分别计算每个字符对应的base64编码值let char1 = str.charCodeAt(i) >> 2; // 取byte1前6位let char2 = (str.charCodeAt(i) & 3) << 4 | str.charCodeAt(i + 1) >> 4; // 取byte1后2位+byte2前4位let char3 = (str.charCodeAt(i + 1) & 15) << 2 | str.charCodeAt(i + 2) >> 6; // 取byte2后4位+byte3前2位let char4 = str.charCodeAt(i + 2) & 63; // 取byte3的后6位// 判断是否需要填充(每次共处理3个输入字符,只需要判断是否存在第二与第三个字符)// 一个输入字符 8 bit,最起码会产生 2个 base64字符if (isNaN(str.charCodeAt(i + 1))) {char3 = char4 = 64; // 第二个字符不存在时,填充末尾2个 =} else if (isNaN(str.charCodeAt(i + 2))) {char4 = 64; // 第三个字符不存在时,填充末尾1个 = }result += base64Table.charAt(char1) + base64Table.charAt(char2) + base64Table.charAt(char3) + base64Table.charAt(char4);}return result;
}// Base64解码
export function decode(str) {let result = '';let value1, value2, value3, value4; // 存储4个base64字符所对应的索引let char1, char2, char3; // 存储解码后的3个原始字符// 处理字符串中异常字符,仅保留base64字符str = str.replace(/[^A-Za-z0-9+/=]/g, '')for (let i = 0; i < str.length; i += 4) {// 从base64编码表中获取字符所对应的valuevalue1 = base64Table.indexOf(str.charAt(i));value2 = base64Table.indexOf(str.charAt(i + 1));value3 = base64Table.indexOf(str.charAt(i + 2));value4 = base64Table.indexOf(str.charAt(i + 3));// 将4个base64字符解码成3个原始字符char1 = value1 << 2 | value2 >> 4;char2 = (value2 & 15) << 4 | value3 >> 2;char3 = (value3 & 3) << 6 | value4;// 解码后字符拼接(最少会有一个字符[依赖value1和value2])result += String.fromCharCode(char1);if (value3 !== 64) result += String.fromCharCode(char2);if (value4 !== 64) result += String.fromCharCode(char3);}return result;
}

uni演示项目gitee仓库:https://gitee.com/pengyue82/JS-base64



总结:其实本来没想写,GPT完全可以搞定,且网上方案一堆,但是想重拾CS的热情,当年学C的时候确实这些计算都笔算的很熟练,所以只是把逻辑组合就好了,虽然现在基本上用不着自己造轮子,但是推理的过程仍然十分有趣
PS:如果文中有理论错误问题,烦请指导,感谢

相关文章:

UNIAPP微信小程序中使用Base64编解码原理分析和算法实现

为何要加上UNIAPP及微信小程序&#xff0c;可能是想让检索的翻围更广把。&#x1f607; Base64的JS原生编解码在uni的JS引擎中并不能直接使用&#xff0c;因此需要手写一个原生的Base64编解码器。正好项目中遇到此问题&#xff0c;需要通过URLLink进行小程序跳转并携带Base64参…...

人工智能|机器学习——K-means系列聚类算法k-means/ k-modes/ k-prototypes/ ......(划分聚类)

1.k-means聚类 1.1.算法简介 K-Means算法又称K均值算法&#xff0c;属于聚类&#xff08;clustering&#xff09;算法的一种&#xff0c;是应用最广泛的聚类算法之一。所谓聚类&#xff0c;即根据相似性原则&#xff0c;将具有较高相似度的数据对象划分至同一类簇&#xff0c;…...

注意力、自注意力和多头注意力的区别

本文作者&#xff1a; slience_me 注意力、自注意力和多头注意力的区别 理解注意力&#xff08;Attention&#xff09;、自注意力&#xff08;Self-Attention&#xff09;和多头注意力&#xff08;Multi-Head Attention&#xff09;之间的区别非常重要&#xff0c;因为它们是自…...

FTP,SFTP,FTPS,SSL,TSL简介,区别,联系,使用场景说明

文章目录 简介FTPFTPSSFTP加密场景选择FTPS还是SFTPFTP、SFTP、FTPS区别、联系和具体使用场景如何使用FTP、SFTP和FTPSSSLTLSSSL和TLS区别和联系&#xff0c;以及使用场景SSL和TLS技术上的区别一些问题隐式的TLS&#xff08;FTPS/SSL&#xff09;或者显式的TLS&#xff08;FTPS…...

路由算法与路由协议

路由选择协议的核心是路由算法&#xff0c;即需要何种算法来获得路由表中的各个项目。 路由算法的目的很简单&#xff1a;给定一组路由器以及连接路由器的链路&#xff0c;路由算法要找到一条从源路由器到目标路由器的最佳路径。通常&#xff0c;最佳路径是指具有最低费用的路…...

dubbo接口自动化用例性能优化

前言 去年换了一个新部门&#xff0c;看了下当前的自动化用例的情况&#xff0c;发现存在三类性能问题&#xff1a; 本地调试运行时等待时间较长&#xff0c;就算是一个简单的case&#xff0c;执行时间都需要1分钟以上单用例执行时间比较长&#xff0c;部分用例执行时间超过2…...

.net core框架

ASP.NET Core 入门 跨平台开源框架 B/S 类与方法 Console 部分称为“类”。 类“拥有”方法&#xff1b;或者可以说方法存在于类中。 WriteLine() 部分称为“方法”。 想要使用方法就要知道方法在哪里 —————————— 执行流 一次执行一段 ASP.NET Core 是什么东西…...

学习大数据,所需要Java基础(9)

文章目录 网络编程实现简答客户端和服务器端的交互编写客户端编写服务端 文件上传文件上传客户端以及服务器端实现文件上传服务器端实现&#xff08;多线程&#xff09;文件上传服务器端&#xff08;连接池版本&#xff09;关闭资源工具类 BS架构服务器案例案例分析BS结构服务器…...

Python元组(Tuple)深度解析!

目录 1. 什么是元组&#xff1f; 2. 创建元组 3.访问元组 4.元组的运算 5.修改元组不可行 6.元组的应用场景 前面的博客里&#xff0c;我们详细介绍了列表&#xff08;List&#xff09;这一种数据类型&#xff0c;现在我们来讲讲与列表相似的一种数据类型&#xff0c;元组…...

排序 Comparable接口、Comparator接口

String类的Comparable接口 1、String类实现了Comparable<String>接口&#xff0c;并提供了compareTo方法的实现&#xff0c;因此&#xff0c;字符串对象&#xff08;即String类型的实例&#xff09;可以直接调用compareTo()方法来比较它们。2、String类的compareTo()方法…...

得帆助力大族激光主数据平台建设,用数据为企业生产力赋能

本期客户 大族激光科技产业集团股份有限公司&#xff08;以下简称“大族激光”&#xff09;是一家从事工业激光加工设备与自动化等配套设备及其关键器件的研发、生产、销售&#xff0c;激光、机器人及自动化技术在智能制造领域的系统解决方案的优质提供商&#xff0c;是国内激光…...

实名认证电子签署:防范合同纠纷,提升交易信任

当今社会&#xff0c;随着数字化和信息化的发展&#xff0c;电子合同已经成为商务活动中常见的签署方式。而在签署电子合同时进行实名认证&#xff0c;是为了确保合同的真实性、合法性和安全性。本文将从法律、技术和实际应用等方面详细解释为什么签署电子合同需要进行实名认证…...

c++ primer中文版第五版作业第十八章

仓库地址 文章目录 18.118.218.318.418.518.618.718.818.918.1018.1118.1218.1318.1418.1518.16位置一using声明 位置二using声明 位置一using指示 位置二using指示 18.1718.1818.1918.2018.2118.2218.2318.2418.2518.2618.2618.2818.2918.30 18.1 此时r是一个range_error类型…...

vue触发真实的点击 事件 跟用户行为一致

<template><div><button ref"myButton" click"handleClick">按钮</button></div> </template><script> export default {methods: {handleClick() {const button this.$refs.myButton;// 创建一个鼠标点击事件…...

Java进程CPU高负载排查

Java进程CPU高负载排查步骤_java进程cpu使用率高排查_YouluBank的博客-CSDN博客 【问题定位】使用arthas定位CPU高的问题_arthas cpu高_秋装什么的博客-CSDN博客 CPU飙升可能原因 CPU 上下文切换过多。 对于 CPU 来说&#xff0c;同一时刻下每个 CPU 核心只能运行-个线程&…...

Linux编程4.1 网络编程-前导

1、内容概述 网络的基本概念TCP/IP协议概述OSI和TCP/IP模型掌握TCP协议网络基础编程掌握UDP协议网络基础檹网络高级编程 2、计算机联网的目的 使用远程资源共享信息、程序和数据分布处理 3、基本概念 单服务与多客户端的进程间通信C/S client server 由于&#xff0c;跨计…...

【微信小程序】传参存储

目录 一、本地数据存储 wx.setStorage wx.setStorageSync 1.1、异步缓存 存取数据 1.2、同步缓存 存取数据 二、使用url跳转路径携带参数 2.1、 wx.redirectTo({}) 2.2、 wx.navigateTo({}) 2.3、 wx.switchTab({}) 2.4 、wx.reLaunch({}) 2.5、组件跳转 三、…...

计算机设计大赛 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…...

ping多个IP的工具

Ping Tool 项目地址 python开发的IP搜索小工具 ping一个网段所有IP&#xff0c;显示结果查看某个ip地址开放监听的端口配置可保存...

Rust 的 Error 如何使用?

在 Rust 中&#xff0c;错误处理是一个重要且核心的概念。Rust 提供了一种强大的类型系统&#xff0c;允许你明确地处理可能出现的错误。std::error::Error trait 是 Rust 标准库中用于表示错误的基础 trait。实现这个 trait 的类型可以被用作错误类型&#xff0c;并且可以使用…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...