base64编码

Base64 是一种基于 64 个可打印字符来表示二进制数据的编码方式。以下从多个方面详细解释:

一、编码目的和应用场景

  1. 数据传输兼容性
    • 在网络通信和数据存储中,有些通信协议和存储系统只能处理文本数据,而无法直接处理二进制数据。Base64 编码可以将二进制数据转换为可打印的 ASCII 字符序列,这样就可以方便地在这些只支持文本的环境中传输或存储。
    • 例如,在电子邮件系统中,邮件内容主要是文本格式。如果要在邮件正文中嵌入二进制数据(如图像、附件等),就可以先将二进制数据进行 Base64 编码,使其变成可打印的字符序列,然后再将其包含在邮件正文中发送。
  2. 数据加密基础步骤(但非加密本身)
    • 虽然 Base64 不是一种加密算法,但它可以作为加密过程的一个辅助步骤。在加密数据之前先进行 Base64 编码,将数据转换为合适的格式,便于后续加密操作和传输。
    • 比如,在一些简单的安全通信场景中,先将敏感数据进行 Base64 编码,再使用其他加密算法(如 AES 等)对编码后的数据进行加密,这样可以在一定程度上隐藏数据的原始格式,增加数据的安全性。

二、编码原理

  1. 字符表和分组方式
    • Base64 使用一个包含 64 个字符的字符表,通常是 “A - Z”、“a - z”、“0 - 9” 以及 “+” 和 “/” 这 64 个字符。另外还有一个用于填充的字符 “=”,在某些情况下会用到。
    • 它将二进制数据以每 3 个字节(24 位)为一组进行处理。因为 24 位数据可以正好分成 4 个 6 位的数据块,而 6 位二进制数可以表示 0 - 63 这 64 个不同的值,正好对应 Base64 字符表中的 64 个字符。
    • 例如,假设有一个二进制数据序列 “110100101011100011001101”,按照 3 个字节一组划分(这里正好是 3 个字节),然后将其拆分为 4 个 6 位的数据块进行编码。
  2. 编码过程中的位操作
    • 对于每 3 个字节的输入数据,首先将第一个字节(8 位)的最高 2 位取出,右移 2 位后得到一个 6 位的数据块,通过 Base64 字符表找到对应的字符作为编码后的第一个字符。
    • 接着,将第一个字节的最低 3 位和第二个字节(8 位)的最高 4 位组合(第一个字节的最低 3 位左移 4 位后与第二个字节的最高 4 位进行或操作),得到第二个 6 位的数据块,同样在字符表中找到对应的字符作为编码后的第二个字符。
    • 然后,将第二个字节的最低 4 位和第三个字节(8 位)的最高 2 位组合(第二个字节的最低 4 位左移 2 位后与第三个字节的最高 2 位进行或操作),得到第三个 6 位的数据块,找到对应的字符作为编码后的第三个字符。
    • 最后,将第三个字节的最低 6 位直接作为第四个 6 位的数据块,找到对应的字符作为编码后的第四个字符。
    • 例如,对于字节序列 “ABC”(ASCII 码分别为 65、66、67),转换为二进制是 “010000010100001001000011”。经过上述位操作后,编码后的 Base64 字符序列为 “QUJD”。
  3. 处理数据长度不足的情况
    • 当输入数据的字节数不是 3 的倍数时,需要进行特殊处理。如果最后剩余 1 个字节,将这个字节的 6 位数据编码为一个 Base64 字符,然后添加两个 “=” 作为填充,表示后面的数据缺失。
    • 如果最后剩余 2 个字节,将第一个字节的 6 位数据和第二个字节的 4 位数据编码为两个 Base64 字符,然后添加一个 “=” 作为填充,表示后面的数据缺失。
    • 例如,对于字节序列 “AB”,经过编码后得到 “QUI=”,其中 “=” 是填充字符。

三、与其他编码方式的比较

  1. 和十六进制编码对比
    • 十六进制编码也是一种将二进制数据转换为可打印字符的方式,它使用 16 个字符(0 - 9 和 A - F)来表示二进制数据。十六进制编码每 4 位二进制数据对应一个字符,而 Base64 是每 6 位二进制数据对应一个字符。
    • 相比之下,Base64 编码后的字符串长度更短。例如,对于同样的 3 个字节(24 位)的二进制数据,十六进制编码后长度为 6 个字符,而 Base64 编码后长度为 4 个字符。
  2. 和 URL 编码对比
    • URL 编码主要用于将 URL 中的特殊字符转换为安全的可在 URL 中传输的格式。Base64 编码更侧重于将二进制数据转换为可打印的文本格式,而 URL 编码主要针对 URL 中的字符进行转换,如将空格转换为 “%20” 等。它们的应用场景有较大差异。

四、C语言实现base64编码

1.以下是一个使用 C 语言实现 Base64 编码的完整代码示例,同时会对代码进行详细解释说明。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Base64编码表
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 进行Base64编码的函数
char *base64_encode(const char *input) {
    int input_len = strlen(input);
    int output_len = ((input_len + 2) / 3) * 4;  // 根据规则计算编码后长度
    char *output = (char *)malloc(output_len + 1);  // 分配内存用于存储编码结果,多分配1字节用于存放字符串结束符'\0'
    if (output == NULL) {
        return NULL;  // 内存分配失败则返回空指针
    }
    memset(output, 0, output_len + 1);  // 初始化为0

    int i, j;
    for (i = 0, j = 0; i < input_len;) {
        // 每次取3个字节一组进行编码
        int a = (unsigned char)input[i++];
        int b = (i < input_len)? (unsigned char)input[i++] : 0;
        int c = (i < input_len)? (unsigned char)input[i++] : 0;

        int index1 = (a >> 2);
        int index2 = ((a & 3) << 4) | (b >> 4);
        int index3 = ((b & 15) << 2) | (c >> 6);
        int index4 = (c & 63);

        output[j++] = base64_table[index1];
        output[j++] = base64_table[index2];
        if (i > input_len + 1) {
            output[j++] = '=';
        } else {
            output[j++] = base64_table[index3];
        }
        if (i > input_len) {
            output[j++] = '=';
        } else {
            output[j++] = base64_table[index4];
        }
    }
    return output;
}

// 测试函数
int main() {
    char input[] = "Hello, world!";
    char *encoded_result = base64_encode(input);
    if (encoded_result!= NULL) {
        printf("原始字符串: %s\n", input);
        printf("Base64编码后: %s\n", encoded_result);
        free(encoded_result);  // 释放动态分配的内存
    }
    return 0;
}
2. Base64 编码表定义
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

这是 Base64 编码所使用的标准编码表,它包含了 64 个可打印的 ASCII 字符,按照一定顺序排列,用于将二进制数据转换为对应的可打印字符形式。

3. base64_encode函数
char *base64_encode(const char *input) {
    int input_len = strlen(input);
    int output_len = ((input_len + 2) / 3) * 4;  // 根据规则计算编码后长度
    char *output = (char *)malloc(output_len + 1);  // 分配内存用于存储编码结果,多分配1字节用于存放字符串结束符'\0'
    if (output == NULL) {
        return NULL;  // 内存分配失败则返回空指针
    }
    memset(output, 0, output_len + 1);  // 初始化为0
  • 首先,通过 strlen 函数获取输入字符串 input 的长度 input_len。然后根据 Base64 编码规则,每 3 个字节的输入数据会编码为 4 个字节的输出数据,所以计算编码后字符串大致长度 output_len(这里 (input_len + 2) / 3 是为了向上取整,保证足够的空间,然后乘以 4 得到最终编码后的长度估计值)。
  • 接着使用 malloc 函数动态分配 output_len + 1 字节的内存空间来存储编码后的结果字符串,多分配的 1 字节用于存放字符串结束符 '\0',使得生成的字符串符合 C 语言中字符串的规范。如果内存分配失败(malloc 返回 NULL),则直接返回 NULL。最后使用 memset 函数将分配的内存空间初始化为全 0,确保其中没有垃圾数据。
    int i, j;
    for (i = 0, j = 0; i < input_len;) {
        // 每次取3个字节一组进行编码
        int a = (unsigned char)input[i++];
        int b = (i < input_len)? (unsigned char)input[i++] : 0;
        int c = (i < input_len)? (unsigned char)input[i++] : 0;

        int index1 = (a >> 2);
        int index2 = ((a & 3) << 4) | (b >> 4);
        int index3 = ((b & 15) << 2) | (c >> 6);
        int index4 = (c & 63);

        output[j++] = base64_table[index1];
        output[j++] = base64_table[index2];
        if (i > input_len + 1) {
            output[j++] = '=';
        } else {
            output[j++] = base64_table[index3];
        }
        if (i > input_len) {
            output[j++] = '=';
        } else {
            output[j++] = base64_table[index4];
        }
    }
    return output;
}

  • 定义了两个循环变量 i 和 ji 用于遍历输入字符串,j 用于填充输出字符串。在 for 循环中,每次尝试取 3 个字节的数据进行编码(实际可能不足 3 个字节,后面会处理这种情况)。
  • 通过 i 依次取出 3 个字节(用 unsigned char 类型转换保证数据的正确处理,防止符号扩展问题),分别存到 abc 变量中,如果已经到达输入字符串末尾,对应字节则赋值为 0
  • 然后按照 Base64 编码的原理进行位运算,将这 3 个字节的 24 位二进制数据拆分成 4 个 6 位的二进制数据块,分别计算它们在 Base64 编码表中的索引值(通过 index1index2index3index4 表示)。
  • 最后根据这些索引值,从 Base64 编码表 base64_table 中取出对应的字符,依次填充到输出字符串 output 中。如果取字节过程中已经超出了输入字符串长度(即输入字节数不足 3 个),则按照 Base64 规则用 '=' 字符进行填充。
4. main函数(测试部分)
int main() {
    char input[] = "Hello, world!";
    char *encoded_result = base64_encode(input);
    if (encoded_result!= NULL) {
        printf("原始字符串: %s\n", input);
        printf("Base64编码后: %s\n", encoded_result);
        free(encoded_result);  // 释放动态分配的内存
    }
    return 0;
}
  • 在 main 函数中,首先定义了一个测试用的输入字符串 input
  • 然后调用 base64_encode 函数对 input 进行 Base64 编码,将返回的编码结果指针存储在 encoded_result 中。如果编码成功(encoded_result 不为 NULL),则分别输出原始字符串和编码后的字符串,并且通过 free 函数释放之前动态分配用于存储编码结果的内存空间,避免内存泄漏。最后返回 0,表示程序正常结束。

### JMeter 中配置并展示并发用户数的图表 #### 使用监听器组件来可视化并发用户数 为了在 JMeter 测试过程中实时监控和记录并发用户的数量,可以利用 `Active Threads Over Time` 或者 `Concurrency Thread Group` 结合 `Aggregate Report` 来实现。这些功能允许测试人员直观地看到不同时间段内的活动线程数目变化情况。 对于想要创建一个显示并发用户随时间变动趋势图的情况来说,“Active Threads Over Time” 是非常合适的选项之一[^1]。此监听器会绘制一条曲线表示整个负载测试期间内活跃线程的数量是如何随着时间推移而改变的。 要设置这样的图形化报告: - 添加一个新的 **Listener**(监听器),选择 "Active Threads Over Time" ```bash 右键点击测试计划 -> Add -> Listener -> Active Threads Over Time ``` - 如果希望保存生成的数据以便后续分析,则可以在该监听器上做进一步设定以指定文件路径用于存储结果数据 另外一种方法是通过安装插件的方式来增强原生的功能支持。例如,使用 “JMeter Plugins Manager”,能够轻松获取更多高级特性如更丰富的统计报表以及更加精细控制的调度机制等[^2]。 当涉及到具体场景下的模拟真实流量模式时,建议采用 `Concurrency Thread Group (CTG)` 替代默认提供的简单线程组。这是因为 CTG 提供了一种更为灵活的方式去定义期望达到的目标级别——既可以通过固定数值也可以基于预估的工作负荷动态调整实际参与执行脚本实例的数量[^3]。 一旦选择了适合自己的方案之后,在设计好相应的参数配置项以后便可以直接运行测试,并观察由上述提到的各种方式所产生的输出效果了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值