为什么编码不同会出现乱码?

简介: 尝试用简单的实例说明乱码产生的原因,当遇到乱码时可以为更好地定位问题提供参考

实为吾之愚见,望诸君酌之!闻过则喜,与君共勉

第一章  情景模拟

第一节 工具准备

准备一些需要的工具,方便后面的虚拟场景

1.1.1 模拟密码本A

密码本A的字符坐标规则:假设一个字符的密文由三部分组成,顺序分别是"U+5600的56"+"表格最上方的坐标"+"表格最左边的坐标",举例"570B"是"國","56E7"是"囧",如下第一个和第二个密码表,这些密文是16进制的格式,下同







1.1.2 模拟密码本B

密码本B的字符坐标规则:假设一个字符的密文由三部分组成,顺序分别是"表格左上角的字符串"+"表格最左边的坐标"+"表格最上方的坐标",举例"87E5"是"囧","87F8"是"國",如下第一个密码表,这些密文也是16进制的格式,下同



1.1.3 密文的加密规则

即我们可能还需要对我们拿到的密文进行再一次的加密,比如”囧”的密文是” "56E7”按照开头假设的密文规则,这是16进制的数,那我们还需要把这个16进制的56E7通过一定的规则,再次加密,针对这两个密码本的加密规则假设如下:

密码本A密文再次加密规则:

16进制密文转换为10进制后对应的范围

16进制数转换为2进制后对应的加密格式

0至127

0xxxxxxx

128至2047

110xxxxx 10xxxxxx

2048至65535

1110xxxx 10xxxxxx 10xxxxxx

65536至2097151

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

比如56E7这个密文再次加密,他转换成10进制是22247,22247在”2048-65535”的范围内,那他的加密格式就是1110xxxx10xxxxxx10xxxxxx,暂且称它为466格式,如何加密呢?如下:

  • 先把56E7转换成二进制为:0101011011100111
  • 按照1110xxxx 10xxxxxx 10xxxxxx的格式,对56E7转换成的二进制0101011011100111进行拆分:

       首先,0101011011100111--------按照4 6 6的格式拆分后--------->0101 011011 100111

       然后,对0101 011011 100111按照466格式进行转换------->11100101 10011011 10100111

       把转换后的111001011001101110100111转换为16进制就是e59ba7,e59ba7就是56E7再次加密的最终密文,这样就由原来的"56E7"是"囧"变成" E59BA7"是"囧",甚至可以根据这个加密方式,生成一个新的密码本C

密码本B的再次加密规则:

密码本B的16进制密文不再进行二次加密,直接使用获得的16进制密文,例如56E7不会与密码本A一样再次加密,直接使用56E7

第二节 漫画情景

1.2.1 情景故事

模拟一个虚构的场景,场景里的元素是:

  • 远在外地的小明
  • 与小明同部门的小丽
  • 安全部门的同学
  • 与小明同部门的小红
  • 一个信息安全非常严格的公司
  • 加密的档案管理

今天,小明需要将一个很重要的数据,告诉公司的小丽把这个数据存到小明自己的档案里:




、

小明发现,他获取到的数据是“闃块噷”,而不是3天前存储的”阿里”,如果小明意识到自己的错误,把小红寄给他的数据先转换成密码本B的密文,再用转换的密文对照密码本A查找呢?

第二章 Mysql的乱码

如果上面的场景,放到数据库里,会一样吗?拿mysql作为例子,测试一下,数据从客户端发送到server并存入表中成为数据然后查询该数据的过程,mysql中控制这个过程的编码的参数主要是character_set_client,character_set_connection,character_set_results,表字符集以及程序字符集等,可以看下文档。

第一节      mysql的情景对应

字符集:
unicode  gbk
字符编码规则:
utf8:只针对unicode,相当于第一章情景中的二次加密
gbk:不对gbk再编码

参数与情景对应:
程序字符集:小明加密数据时使用的密码本A
character_set_client:小明在寄信时,写错了数据加密方式,写的是密码本B,而不是A
character_set_connection:安全规则,需要转换的加密格式
character_set_results:寄信时需要使用的加密格式
表或者库字符集:小明的档案的加密格式
Server端处理:小丽/小红

第二节      mysql测试

2.2.1 第一次测试

参数设置:
程序字符集:utf8
character_set_client:utf8
character_set_connection:utf8
character_set_results:utf8
表或者库字符集:utf8
Server端处理:mysql program 

测试结果:无乱码

2.2.2 第二次测试

参数设置:
程序字符集:utf8
character_set_client:gbk
character_set_connection:utf8
character_set_results:utf8
表或者库字符集:utf8
Server端处理:mysql program 

测试结果:只设置set character_set_client=gbk后,查询乱码

2.2.3 乱码猜猜猜

结合第一章的场景,为什么乱码呢?

2.2.3.1 第一步处理

程序将"阿里"以utf8编码进行转换发送(unicode转utf8与情景中的规则一致),但是不小心在session中设置了character_set_client=gbk,character_set_connection =utf8,character_set_results=utf8,类似如下现象:

形状:阿里

Utf8方式下的16进制编码值:E998BF E9878C                   

二进制:11101001 10011000 10111111 11101001 10000111 10001100(utf8将2个汉字转换后6个字节)

 

2.2.3.2 第二步处理

到达server端,server通过character_set_client=gbk知道客户端发过来的数据是gbk编码的(实际是utf8编码的,客户端不小心写错了),那server端就按照gbk来解码了,解码后如下:

二进制:11101001 10011000 10111111 11101001 10000111 10001100(程序端的两个汉字经过utf8转换后的二进制数据,一共6字节,但是server端不知道,因为server通过character_set_client=gbk得知,这不是utf8,这是gbk的,我要按照gbk来解码)

gbk转换后的16进制编码值:E998 BFE9 878C(通过这个编码,查找gbk的码表,获取他的形状为:闃块噷)


2.2.3.3 第三步处理

Servre还需要检查character_set_connection参数,发现character_set_connection=utf8,而之前是gbk,那就需要将gbk的这三个字节转换为utf8,怎么转换呢?按照第一章的情景,先转unicode(密码本A),再将得到的unicode再次编码为utf8:

“闃块噷“三个字符的unicode编码是 95c3 5757 5677

转换成二进制:10010101 11000011 01010111 01010111 01010110 01110111(这三个汉字是6个字节)

通过unicode,再转换为utf8的实现方式,实现方式如下:


首先转换95c3( 1001010111000011),他的范围在第三行(3字节)

1001 010111 000011,根据第三行的格式,从低位往高位的顺序,按照格式分成4 6 6 的格式

按照格式填充,填充后:11101001 10010111 10000011,填充后转换成16进制是e99783,则”闃”在utf8中就是”e99783”,同样,”块”在utf8中就是” e59d97”,” 噷”在utf8中就是” e599b7”, 于是转换后的结果就是:

编码:E99783 E59D97  E599B7

二进制:111010011001011110000011111001011001110110010111111010000000000000000000

2.2.3.4 第四步处理                          

server端处理好之后,继续向下走,准备存储数据了,检查了存储的表是utf8的,不需要转换了,直接存储

编码:E99783 E59D97  E599B7

二进制:111010011001011110000011111001011001110110010111111010000000000000000000

2.2.3.5 查询返回

程序插入完成后,想查询下之前插入的数据,于是客户端在当前session下执行了select操作,server端收到请求后,去表里找数据,找到了之前写入的数据

111010011001011110000011111001011001110110010111111010000000000000000000

server检查character_set_results=utf8,与表的字符编码是一致的,那就不需要转换了,直接把111010011001011110000011111001011001110110010111111010000000000000000000给程序了,程序收到后,就解码111010011001011110000011111001011001110110010111111010000000000000000000,因为程序本身也是utf8的,不需要转换,于是按照utf8来解码数据,111010011001011110000011111001011001110110010111111010000000000000000000的16进制是E99783E59D97E599B7(符号是闃块噷,乱码了)

 

目录
相关文章
|
资源调度 监控 负载均衡
浅析PM2实用入门指南
PM2 是一个守护进程管理器,可以用它来管理你的node进程,负责所有正在运行的进程,并查看node进程的状态,也支持性能监控,负载均衡等功能。使用起来也是非常简单
2482 0
|
7月前
|
消息中间件 人工智能 边缘计算
空地协同让电力巡检更智能 ——从人工攀爬到立体监测的技术演进
这是一套“空地协同”智能电力巡检系统:无人机搭载RTK+20倍变焦相机自主巡线,工程车集成AI边缘计算(Jetson AGX Orin)与红外检测,实现厘米级定位、小目标识别(92%+准确率)、无网环境本地分析+断点续传。系统已落地应用,显著降低人工登塔风险。
644 4
|
11月前
|
存储 SQL 安全
全球数据安全新范式:阿里云DAS+DTS为企业打造合规出海“护航舰”
阿里云DAS与DTS推出覆盖数据跨境、实时脱敏、加密保护、合规审计的一站式安全解决方案,助力企业高效应对全球合规风险。
|
人工智能 自然语言处理 计算机视觉
StyleStudio:支持图像风格迁移的文生图模型,能将融合参考图像的风格和文本提示内容生成风格一致的图像
StyleStudio 是一种文本驱动的风格迁移模型,能够将参考图像的风格与文本提示内容融合。通过跨模态 AdaIN 机制、基于风格的分类器自由引导等技术,解决了风格过拟合、控制限制和文本错位等问题,提升了风格迁移的质量和文本对齐的准确性。
991 8
StyleStudio:支持图像风格迁移的文生图模型,能将融合参考图像的风格和文本提示内容生成风格一致的图像
|
运维 安全 Devops
DevOps实践:自动化部署的脚本编写技巧
【9月更文挑战第24天】在DevOps文化中,自动化部署是提升效率、减少人为错误的关键。本文将引导读者了解自动化部署脚本的编写方法,从基础命令到复杂逻辑,逐步深入。你将学会如何用代码简化日常任务,让重复工作变得轻松愉快。让我们一起探索自动化的世界,释放你的创造力!
609 2
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
712 9
|
机器学习/深度学习 算法 数据安全/隐私保护
图像滤镜艺术---人脸编辑(五官微调+瘦脸美型)
原文:图像滤镜艺术---人脸编辑(五官微调+瘦脸美型) 写本文的目的,实际上是对目前人脸美型这一块技术做个总结,跟大家 分享一下!目前提到美颜算法,大家都会想到磨皮美白 /大眼瘦脸,实际上做好 美颜这件事情,关乎的不仅仅是这些,还有五官的协调比例等,今天我们主要说一下五官的微调,这里我直接称之为人脸编辑吧。
4154 0
|
测试技术 API 开发者
从零开始学习 form-data:轻松上手数据交互技术
在 Web 开发和 API 设计中,表单数据的传输是一项基本的需求。本文着重介绍form-data—一种广泛应用于数据传输的编码方法。
|
算法 安全 数据安全/隐私保护
【防网盘在线解压】Peazip 豌豆压缩 v9.7.0
【防网盘在线解压】Peazip 豌豆压缩 v9.7.0
612 7
【防网盘在线解压】Peazip 豌豆压缩 v9.7.0
|
数据可视化 JavaScript 前端开发
使用ECharts创建动态数据可视化图表
使用ECharts创建动态数据可视化图表

热门文章

最新文章