Tomcat内核之ASCII解码的表驱动模式

我们知道Tomcat通信是建立在Socket的基础上,而套接字在服务器端和客户端传递的报文都是未经过编码的字节流,每8位组成1个字节,计算机以二进制为基础,这是由于使用晶体管的开合状态表示1和0,这样8个电晶体管就可以组成一个字节,这正是应用层使用的最小单位——字节。

在通过Socket进行网络通信的程序中,假如我们在接收到报文时不知道通过什么编码才能正确解码,最好的办法就是用Socket最底层的输入装置读取字节流,在确认编码后再对这些字节流进行转码,否则产生解码错误。我们常见的编码有ASCII、GB2312、UNICODE、UTF-8等等,除此之外还有很多其他编码,为什么会有这么多不同的编码?

ASCII编码即American Standard Code for Information Interchange,作为美国标准信息交换编码,并且计算机刚开始只在美国流行,所以当时所有的计算机都使用ASCII编码,ASCII编码是由8比特组成,从0到127分别用于表示不同的字符,包括各种符号、英语字母、阿拉伯数字等,由于128种字符只需7位即可完成编码,所以最高位被0填充。这128个字符已经完全满足使用英语的美国人,英语单词可以通过拆分成字母后用ASCII码表示。

后来随着计算机的迅速发展,其他国家相继引入计算机,他们发现这些编码根本不够对他们本国文字编码,ASCII码一共8位,最多也只能表示256个字符,于是他们对最高位做文章,其中0-127已经被美国使用并成为标准,为了兼容考虑肯定不能改动,剩下128-255可供使用,但很快剩下的128个编码又被用完,现在唯一能做的就是使用两个甚至更多个字节来表示一个字符,每个国家都有自己的规定,于是中国编制了GB2312编码,为了兼容ASCII,它规定一个字节如果小于等于127则表示ASCII,如果两个大于127的字节连在一起则表示汉字,而且两个字节的值都在一定的范围内。经过一轮扩展后已经基本解决汉字编码不足问题。

再后来很多国家都按自己规定给自己的文字编码,对其他国家的编码一概不认识,情况一度混乱。接着国际标准化组织推出UNICODE编码,它要把全世界所有文字符号都包括进来,使用两个字节16位对所有字符进行编码,同时为了保证兼容ASCII码,低七位仍用于表示ASCII码原来的字符。通过UNICODE确实是把世界所有字符都统一起来了。

UNICODE编码虽然统一了所有字符,但还存在一个问题,如果是英文字符其实用一个字节已经足够,但使用UNICODE却必须要搭上另外一个毫无意义的字节,在网络传输过程中则意味着要多传输一倍无用的报文。于是引入UTF-8编码,它属于UNICODE的一种实现,它是一种变长的编码方式,在UTF-8规定的实现下可以用一个字节表示ASCII码表示的所有字符,避免了多余的空间浪费。

出了上面几种常见的编码,还有很多其他编码,不同编码指定的规则也不同,但基本都对ASCII做了兼容处理,可以说ASCII是最基础的,这节正是讨论ASCII码解密的常用方法——表驱动模式。

谈到web容器其实就是基于HTTP协议通信建立起两端通信,通过socket实现报文传输,传输过程肯定设计编码的约定,如果没有一个约定将导致消息解码错误。HTTP报文包括三部分:请求行、请求头和请求体(详细可参加前面HTTP协议章节),HTTP协议约定请求行和请求头必须用ASCII编码,这样才能把所有基于HTTP协议通信服务器统一起来,以免造成不同系统默认编码带来混乱。Tomcat接收到ASCII编码的报文,因为ASCII码长度为1字节(8位),java的byte长度也是1字节,两者刚好符合,所以在java中套接字接收到的报文是使用字节类型的数组进行缓冲存储。一般而言,我们比较关心ASCII码向数字、字母及几个特殊符号的解码,通过他们已经足以组成常用的词语语句。如下表,ASCII码中48-57分别表示数字0-9,65-90分别代表A-Z,97-122分别代表a-z。

在解码的过程涉及一些逻辑处理,例如解码后是否为英语字母、是大写还是小写、是否为数字、是否为空白符、转换为其他类型、大小写转换等等。我们惯用的办法是直接用if-else进行判断,如要判断一个ASCII编码是否为英语字母就判断编码是否在65到90、97到122之间,而表驱动思想则不是这样做,它把一张是否为英语字母的结果表放在内存,如下图所示,数组中标为t的表示是英语字母,数组的值即是结果。

类似地,根据其他需求可以在内存中存放更多张表,把判断的逻辑结果事先算好,直接获取数组值便是需要的结果。表驱动模式经常被用于取代很多if-else、switch-case逻辑判断语句中,它的使用有利于提高代码的可读性和维护性。Tomcat使用的ASCII表驱动类为org.apache.tomcat.util.buf.Ascii.java。

时间: 2024-12-20 01:21:35

Tomcat内核之ASCII解码的表驱动模式的相关文章

【转】ASCII码对应表chr(9)、chr(10)、chr(13)、chr(32)、chr(34)、chr(39)

chr(9) tab空格       chr(10) 换行      chr(13) 回车        Chr(13)&chr(10) 回车换行       chr(32) 空格符       chr(34) 双引号       chr(39) 单引号 chr(33) !        chr(34) "        chr(35) #        chr(36) $        chr(37) %        chr(38) &        chr(39) '   

[lua]原来这才是表驱动的正确表达方式

曾经写了个很煞笔的脚本模拟switch..case语法形式.[lua]尝试一种Case语法糖 而今实际项目应用中突发,原来这才是正确的表驱动方式表达.如下所贴: function event_do( event ) -- event:string local handler ={} function handler.touchBegin() print("handler.touchBegin") end function handler.touchEnd() print("h

表驱动与工厂模式

关于表驱动 首次接触表驱动,还是在毕业不久之后.当时某部门经理给我们讲解重构,即<重构:改善既有代码的设计>一书中简化条件表达式部分,关于if语句的处理,将其替换为多态形式,例如说工厂模式.但是即使替换为工厂,switch或者if的判断依旧不能去除,那么有什么办法解决这个问题呢? 当时我还在研究STL源码,想到了traits编程技术,可以在编译期解决if的判断问题(虽然有这个想法,但是一直没有实现成功).各路大牛提出了不同的见解,大家基本上都同意一条:使用"表"来解决.当时

汇编相关(ASCII码字符表 DEBUG命令 BIOS功能调用表 DOS功能调用表 汇编语言错误信息表)

汇编相关 一些关于汇编的常用东西,包括: ASCII码字符表 DEBUG命令 BIOS功能调用表 DOS功能调用表 汇编语言错误信息表 ASCII码字符表 DEBUG命令 BIOS功能调用表 DOS功能调用表 汇编语言错误信息表

黑盒测试用例设计-判定表驱动方法

5.判定表驱动方法 前面因果图方法中已经用到了判定表.判定表是分析和表达多逻辑条件下执行不同操作的情况的工具.在程序设计中可作为编写程序的辅助工具.把复杂的逻辑关系和多种条件组合的情况表达得较明确. (1)   判定表结构 判定表通常由4部分组成,如下图所示: ·条件桩(condition stub):列出了问题的所有条件.通常认为列出的条件的次序无关. ·动作桩(action stub):列出了问题规定可能采取的操作.这些操作的排列顺序没有约束. ·条件项(condition):列出针对它所列

Table-Driven Design 表驱动设计

注:本文所有代码来自 http://www.codeproject.com/Articles/42732/Table-driven-Approach 在许多程序中,经常需要处理那些拥有种种色色不同特性的实体,最直接的思路是用case语句或者if-else语句处理这些不同的实体.然而,如果这类实体的数量若足够庞大,将会产生大量代码,臃肿并难以整理和维护. 先通过一对实例感受一下: // A text adventure game if(strcmpi(command, "north")

红外遥控--红外遥控的编解码以及识别驱动

红外遥控的编解码以及识别驱动        由于不同的遥控器的编码格式可能是不同的,这里只是目前我所用的这款遥控器的单片机识别程序以及可以对未知编码格式的红外遥控器进行解码的方法. 红外遥控器的编码一般由引导码.系统码.系统反码.功能码.功能反码.固定停止码或者校验码等组成. 1.实例 红外遥控器解码识别程序 作为例子的遥控器是属于一种空调遥控器的编码.(以后所说的T都是指400us的时间) 其编码格式由引导码+固定头码+功能码+校验码组成. 引导码脉冲为8T的高电平和8T的低电平. 位1脉冲宽

表驱动的认识以及用法——原创---非抄书

表驱动是什么:通过查找数据表来代替复杂的逻辑结构(如 if ... else ......, switch等): 表驱动的优点是: 1. 将编程的重心调整到解决问题上,而不是复杂的逻辑判断:2. 增加了程序的灵活性,易添加,易修改:3.数据驱动,如果将数据写入文件,每次启动时,从文件中读取,那么,如果要修改一些变量,可能直接修改数据文件,而不是去修改程序结构: 表驱动的三种方法:1.直接驱动法: 你需要找什么,指定索引,就可以给你立即返回索引在表中对应的元素 或者动作: 案例1:(一维查找:即可

查询优化--小表驱动大表(In,Exists区别)

Mysql 系列文章主页 =============== 本文将以真实例子来讲解小表驱动大表(In,Exists区别) 1 准备数据 1.1 创建表.函数.存储过程 参照  这篇(调用函数和存储过程批量插入数据)  文章中的第 1-7 步,注意,不要执行第8步 1.2 插入数据 现在来执行第8步. 1.2.1 向 Department 表中插入 100 条记录 CALL insert_dept(1000, 100) 1.2.2 向 Employee 表中插入 100000 条记录 CALL in