【常见的编解码场景】

在软件领域内,有诸多编码解码的应用场景,而对于编码一词的使用,在不同场景下也会有不同的语义表达,很多软件开发人员不堪其困扰,至少我本人是经历了很波折的一些过程。

举几个场景,比如:

  1. 字符集跟字符编码有什么关系,字符集就是字符编码么?
  2. 乱码,从网络上下载的文件,本地打开乱码到底是为何?
  3. dubbo请求链路中,编解码是怎么处理的,dubbo的编解码跟其他场景的编解码有何不同?
  4. Http body中header中定义的charset跟编码,压缩的关系是什么?
  5. Http url中文场景下,在浏览器中为何会出现百分号?
  6. http协议中定义的编码方式和字符集,分别是什么意思?
  7. http的请求过程中,到底哪些地方有编码,序列化,整个过程是怎样的?

本文总结并梳理在日常工作过程中,编解码的一些场景以及不同场景下编解码语义上的一些差异,希望在沟通对焦以及阅读相关文档的过程中对于编解码的含义,更聚焦和明确,对大家的日常工作有所帮助。

一,编码与解码

哲学中成对出现的概念。
在讲清楚这一对矛盾体之前,先试着给它们下个定义:

  • 编码是信息从一种形式或格式转换为另一种形式的过程;
  • 解码是编码的逆过程。

在计算机领域,1和0是计算机存储和识别的最小单元,计算机外的信息转化成计算机能识别的形式就需要编码了。当然在计算机领域内部,也存在着各种格式转换(也称为编码),比如TCP/IP四层协议转换,各层的格式是不同的;应用进程中,对象转成字节码,转成json,xml等。

区分在各种不同的场景下编码的具体语义,可能会有点让人头疼!我们把范围画小些,聚焦下,我们讲述的是计算机应用内,应用间,网络通信,数据存储等场景下的编码;该种形式的编码最终目的是存储(持久化到磁盘)和传输(网络通信,或应用进程通信)。
我们以软件从业人员常见的几种场景开始讲起:

1.1 字符编解码

我们规范下本文的语义:字符编码指的是字符转换成字节,字符解码是从字节转换成字符。

所有的软件开发人员都遇到过乱码的问题,比如:在文本存储时,选择gb2312编码保存中文汉字,这时候使用utf-8编码格式打开文本,就会出现乱码,如下:
在这里插入图片描述

字符集和编码

至于为何会乱码,在讲清楚乱码原因之前,我们先对焦两个概念:字符集和编码格式, 这两个概念在很多场景下总是混在一起,我们有必要先对齐,讲清楚。
● 字符集用于用户展示,比如:“中国”二字使用gbk字符集时,映射为:D6D0 B9FA;而在unicode字符集下映射为:4E2D 56FD。 当使用错误的字符集去展示时,乱码就出现了。
● 编码用于存储以及网络传输,gbk既是字符集也是编码格式,unicode是字符集,utf-8是其常用的编码格式(其他还有utf-16,utf-32等)。

编解码过程分析

有点绕,我们以文本编辑器(vi等)为例,描述下整个过程:在mac os的LANG="zh_CN.UTF-8"的前提下,内存中的字符集使用unicode,我们使用vi编辑器打开一空文本,输入’中国‘二字,‘中国’两个字在内存中对应的字节为:4E2D 56FD,大家在屏幕上看到了‘中国’两个字;当保存时,使用utf-8进行编码,变成了:E4B8AD E59BBD,存储到磁盘。文件的字符集和编码方式为:UTF-8 Unicode text

admin@admindeMacBook-Pro ~ % cat test.txt 
中国 

admin@admindeMacBook-Pro ~ % file test.txt 
test.txt: UTF-8 Unicode text

当我们重新打开文件时,数据从磁盘加载到内存,使用utf8解码, 使用unicode字符集,内存中存储为:4E2D 56FD,用户界面展示出 ‘中国’二字。
另外说明下,gbk既是一种字符集也是编码格式,当我们os环境是gbk且使用gbk编码存储时,内存以及磁盘存储都是D6D0 B9FA。
这里可能有同学会问了,为何unicode不使用4E2D 56FD直接存储而使用utf8存储呢,存储的字节反而更多更长了? 这是因为unicode是定长的编码方式,每个字符用16byte存储;而utf8是变长的编码方式,兼容Asccii编码,英文字符只需要8byte存储,对于大部分存储英文字节的场景,在空间上更有优势。

“中国”二字使用不同的字符集,对应的byte码如下:
● unicode表示为: 4E2D 56FD
● UTF-8表示为: E4B8AD E59BBD
● GBK表示为: D6D0 B9FA

编解码举例

我们仍然以mac系统(LANG=“zh_CN.UTF-8”)为例,分别对比下,英文字符“ab”和中文字符“中国”的存储以及显示器展示,

** 对于英文字符“ab”来说 **,
磁盘存储时使用utf-8编码,十六进制表示为“6162”;
读取到内存中时,十六进制对应的是 “00610062”;
显示器前,unicode字符集映射,用户看到则的是“ab”
“ab”字符的编码解码以及显示器展示的过程表示如下:
在这里插入图片描述

** 对于中文字符“中国”来说** ,
磁盘存储时使用utf-8编码,十六进制表示为“E4B8ADE59BBD”;
读取到内存中时,十六进制对应的是 “4E2D56FD”;
显示器前,unicode字符集,用户看到则的是“中国”
编码解码以及显示器的展示过程表示如下:
在这里插入图片描述

1.2 http url编码

讲完了文本字符编码后,我们再看一下另一种常见的编码方式:http url编码。
RFC3986文档对Url的编解码问题做出了详细的讲述,指出了哪些字符需要被编码,以及编码规则是什么,如下:

Url中只允许包含以下四类字符:
1、英文字母(a-zA-Z)
2、数字(0-9)
3、-_.~ 4个特殊字符
4、所有保留字符

关于保留字符,RFC3986中指定了以下字符为保留字符(英文字符): ! * ’ ( ) ; : @ & = + $ , / ? # [ ]。 Url可以划分成若干个组件,协议、主机、路径等。有一些字符(😕?#[]@)是用作分隔不同组件的。例如:冒号用于分隔协议和主机,/用于分隔主机和路径,?用于分隔路径和查询参数,等等。还有一些字符(!$&'()*+,;=)用于在每个组件中起到分隔作用的,如=用于表示查询参数中的键值对,&符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进行编码。

以上范围外的字符,编码规则如下:
○ URL 编码使用 “%” 其后跟随两位的十六进制数来替换。
○ URL 不能包含空格。URL 编码通常使用 + 来替换空格。

所以,对应url中有中文的场景,我们需要对其进行编码,之后再进行网络传输,比如
“https://www.baidu.com/中文” 在浏览器发送网络请求前,会编码成:“https://www.baidu.com/%E4%B8%AD%E6%96%87” 进行传输。

这也是为什么我们在浏览器中看到百分号的原因。

1.3 http body编码

在http协议传输的过程中,除了url会进行编码外,对于body的内容也会进行编码。

对于http请求,服务端(比如:tomcat)在接受到post请求后,会读取请求头content-type进行body内容的解码,当content-type没有配置时,默认使用application/x-www-form-urlencoded; charset=UTF-8进行解码

对于http服务端返回的内容,通常来说,浏览器会先按照响应头Content-Type的编码设置来解析文本(若响应头Content-Type没有设置编码,浏览器通常会使用默认编码来解析文本),如果在解析过程中发现http

<meta HTTP-equiv="Content-Type" content="text/html; charset="xxx" />

设置时,会更换编码重新读取body内容;

1.4 压缩编码

其实对于body内容的传输,除了进行字符编码外,为了优化网络传输的效率,通常会对传输的内容进行压缩,比如,我们在F12打开浏览器控制台跟踪请求过程时,在http协议中,经常看到如下的header信息:
accept-encoding: gzip, deflate, br
Content-type: application/json; charset=utf-8

这里注意下:在http协议的场景中,定义utf-8为字符集,gzip,deflate等为编码格式,大家注意区分。

1.5 对象编码

除了以上字符编码,我们在一些框架中经常看到编码解码的定义,我们以netty和dubbo为例讲述下这个过程。dubbo其实是基于netty做的编码解码,但是在rpc的使用过程中,比netty更贴近用户层,我们分别讲述下:

netty框架中的编码解码

解码器负责 解码“入站”(inBound)数据从一种格式到另一种格式,解码器(处理入站数据)是抽象ChannelInboundHandler的实现。开发中中使用解码器很简单,就是将入站数据转换格式后
传递到ChannelPipeline中的下一个ChannelInboundHandler进行处理;对于解码器,Netty中提供了抽象基类ByteToMessageDecoder,MessageToMessageDecoder,ChannelDuplexHandler等。
编码器负责 编码“出站(outBound)”数据从一种格式到另一种格式,编码器(处理入站数据)是抽象类ChannelOutboundHandler的实现。对于编码器,Netty中主要提供了抽象基类ChannelDuplexHandler和MessageToByteEncoder等。

dubbo框架的编码解码

在rpc框架dubbo中,对请求内容会进行编码codec,序列化serialization后进行网络传输。Dubbo支持多种通信协议,如dubbo,http,rmi,webservice等,默认使用Dubbo协议。作为通信协议,有一定的协议格式和约定,而这些信息业务上并不需要关注。而是由Dubbo框架在处理流程中,进行添加和解析,这部分内容也成为编码解码。
我们看下dubbo的协议头格式(dubbo处理过程中动态添加和解析):
在这里插入图片描述

再对照dubbo的架构,看下编解码逻辑在整体流程中的位置:
在这里插入图片描述

二, http链路中的编解码

最后,我们以浏览器提交表单(post请求,默认使用header: content-type: application/x-www-form-urlencoded)为例,看下处理过程中,编码解码的过程

2.1 浏览器的请求过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnKmLhD1-1653790361150)(http://showdoc/server/index.php?s=/api/attachment/visitFile/sign/8d137c136f91c5cc14f3397b0eba75c6)]

  1. 请求头编码,主要是对url进行编码
  2. 请求的header信息编码,(尽量不要有中文,浏览器会把它编码成%格式,注意:有些http服务端不能解析)
  3. body参数拼接成字符串并编码,比如
    id=6999126262128493315&content=你好
    会被编码成
    id=6999126262128493315&content=%E4%BD%A0%E5%A5%BD
  4. 组装http请求文本(requestLine+header+body)
  5. 以上字符使用utf-8编码成二进制字节
  6. 网络传输,发送到服务端
2.2 对于服务端的返回数据,浏览器的处理过程

在这里插入图片描述

  1. 网络传输,
  2. 浏览器接受到二进制数据
  3. 解析responseLine+header并获取body的压缩算法和字符集
  4. 使用gzip,deflate或其他压缩算法对body进行解压缩
  5. 使用字符集进行解码,在内存中表示为unicode形式
  6. 浏览器页面渲染

三, 参考

  1. RFC3986: https://datatracker.ietf.org/doc/html/rfc3986
  2. RFC2616: https://www.cnblogs.com/Kimbing-Ng/p/12411017.html
  3. dubbo框架设计:https://dubbo.apache.org/zh/docs/v2.7/dev/design/
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解码器网络结构是一种常用于序列到序列任务的神经网络结构,其中码器负责将输入序列转换为固定长度的表示,而解码器则使用该表示来生成输出序列。下面是一些常见解码器网络结构: 1. 递归神经网络(RNN):RNN 是一种经典的解码器网络结构,它通过递归地处理序列中的每个元素,并将先前的隐藏状态传递给下一个时间步。常见的 RNN 变体包括长短期记忆网络(LSTM)和门控循环单元(GRU)。 2. 卷积神经网络(CNN):CNN 在计算机视觉任务中广泛应用,但也可以用于序列数据。CNN 通过在输入序列上应用一系列卷积层和池化层来提取特征,并将其转换为固定长度的表示。 3. 注意力机制(Attention):注意力机制是一种增强解码器性能的技术。它允许解码器对输入序列中不同位置的信息分配不同的权重,以便在生成输出时更加关注相关的部分。注意力机制常用于基于 Transformer 的模型中。 4. Transformer:Transformer 是一种基于自注意力机制(Self-Attention)的解码器网络结构。它通过在码器和解码器中使用多头自注意力机制来捕捉输入序列的全局依赖关系,并在生成输出序列时实现更好的并行计算。 这些是解码器网络结构的一些常见例子,每种结构都有其适用的场景和优势。研究者们还在不断提出新的改进和变种,以提高解码器的性能和效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值