网络编程中的编码问题汇总

应用程序中的编码问题让人头疼,一直是这样,今天下午就被数据库编码错误搞的头疼不已。

那么,就决心好好总结一下编码带来的问题,争取让自己对整个编码体系有一个清晰的认识。

从编码问题的产生说起

我们知道,计算机是美国人发明的,人家的英语体系总从来就只有26个英文字母和一些数字、特殊字符等,为了储存文字信息,于是使用了最早的ascii码进行字符编码。而后来由于计算机的普及,多国语言文字变得重要起来,于是多语言的特性成为了计算机的必备,各国进行各国的国家标准编码,中国的便是GB2312(1980年),而后1995年又颁布了《汉字编码扩展规范》(GBK),GBK与GB2312相兼容,但又增加了一些兼容汉字,方便了和Big5码等进行转换。这套GBK编码,逐渐成为了中国计算机的主流编码。

Unicode字符集和UTF-8编码

随着计算机的发展,往往一款软件不但要兼容一个国家的语言,还要兼容许多国家的语言,尤其是亚洲国家中日韩三国,光中文常用字符就有7000,所以要解决这么多文字的编码问题,就需要用更多规模的表示,Unicode是一个巨大的字符集,囊括了世界各地的语言,这样编码就更为统一和方便了。但Unicode并没有规定这些字符具体应该怎么样在计算机中存储,虽然字符集是全的,但计算机中要兼顾效率和方便等问题,UCS-2是其中的一种常用方案,采用两个字节来编码一个字符,这和ascii码不兼容,而且还有一个大问题,UCS-2并不能表示全部的汉字,汉字的简繁体加起来总共有六七万,UCS-2只有65536个编码,根本存不下,所以只收入了大部分常用字。也有表示所有汉字的方案UCS-4,不过4个字节用来存储汉字,效率就较为低下。

UTF是“UCS Transformation Format”的缩写,是Unicode字符集的一类高效实现方式。

UTF-8是我个人比较喜欢的一种编码方式,它是一种针对Unicode的可变长度字符编码,又称为万国码。它使用1-6个字节进行编码,最前面128个编码内容和ascii码兼容,所以我们用UTF-8编写纯英文文本是和ascii码几乎一样的。(注意我说的是几乎)。

如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节。而如果UNICODE字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但这样的UNICODE字符往往是生僻字,极为少见。

这种编码的思想和哈夫曼编码是类似的,将高频字符缩短,低频字符变长,使得整体的编码效率更优。

我以前有段时间,就经常将Unicode和UTF-8搞混了,Unicode是字符集,网上不严格的情况也指Unicode字符集的常用编码UCS-2,也就是用两个字节编码的Unicode码。

一些常见系统的编码:

VC 6.0                        Ascii码

VS2008 - 2013           UCS-2(开启Unicode后)

Windows中文版         GBK

Linux(andorid)       UTF-8

Mac OX                      UTF-8

JAVA                           UCS-2

Python2                      Ascii (byte)

Python3                      UCS-2

注:操作系统所述都是默认编码,这三种主流操作系统的系统编码都是可以更改的。

MBCS(Multi-Byte Character Set)和内码表(codepage)

再介绍两个字符集中较为深入的概念,MBCS和CodePage。

MBCS(Multi-Byte Chactacter System,即多字节字符系统),是所有多字节编码方案的总称,MBCS 编程主要用于为国际市场编写的应用程序。由于往往是针对一国市场只有一种文字,那么为了节约资源,往往将这些文字用双字节或尽量少的字节的方式进行保存。

因为这些双字节文字和ANSI是混和在一起的,为了加以区别,Windows将这些字符的最高位置为1(即这些双字节文字的每个字节都>=127),所以这种表示法可以表示 127x127 约一万多种非ANSI文字 ,其本上可以表示任何一种语言的常用文字了。于是,Windows为每一个区域版本,都制定了分别独立的文字编码,这就是MBCS(多字节码)。

而这些分页后的编码方式,都被保存成了不同的CodePage(内码表,这里内码的意思是机器内部编码,相对于外码,外部输入文字用的编码,例如拼音、五笔、郑码等),例如中文就是大家熟知的CP936。要注意,这种编码方式是早期windows独有的,由于使用较早,应用也十分广泛,而CP936和GB2312-80在编码上则是几乎一样的(此处见Wiki百科——汉字内码扩展规范),后来扩展GBK后,CP936也进行了同样的扩展。

此技术的使用最早追溯到MS-DOS3.3(1987年4月发行)向IBMPC用户引进了内码表的概念,Windows也使用此概念。

内码表成为了系统进行多语言编码及转换的重要工具。当然,Unicode码也被收入CodePage中。

说白了,MBCS和CodePage就是计算机解决多字节编码问题的通用手段,各种区域编码可以在其中找到对应编码的映射的,Unicode和UTF-8也是可以在其中找到对应的映射的。

常见的CodePage

932 —日文

936 —简体中文(GBK)

949 —韩文

950 —繁体中文(大五码)

1200 —UCS-2LE Unicode 小端序

1201 —UCS-2BE Unicode 大端序

1252 —西欧拉丁字母ISO-8859-1.

65000 — UTF-7 Unicode

65001 — UTF-8 Unicode

计算机是如何显示文字的呢?

计算机要对文字进行存储后就需要显示出来,而我们的液晶屏都是一个个的像素点组成的,这就必须要对文字进行渲染绘制,发送到显卡中进行栅格化和显示等操作。

Dos下最简单,利用主板BIOS就能对ascii码进行点阵化输出。简单的我们就不再多谈,windows下是如何对文字进行绘制显示的呢?

字库

我们都知道,显示字体除了要有文字的编码,还需要有显示用的字的样式,这就是 字库,windows下的fonts文件夹大家应该都十分熟悉,更改或删除字库就是就是文件的移动而已。而字库实际上也有不同的种类的,构建原理也不都相同。

最早的字库是点阵字库,这种字库看起来和黑白图片貌似没有什么大区别,就是记录像素是黑还是白,我们用windows自带的字库编辑程序,就可以处理这种字库。

这种字库的缺点也是显而易见的,首先是缩放不易,在小字体和大字体显示时都容易失真走样,而且占用空间较大。

矢量轮廓字库,这种字库是用的矢量图原理进行存储的,将外部边界抽象成数学上的矢量线段,可以方便的缩放旋转等操作。缺点则是连续性不好,放大后就变出行了折痕,效果不够理想。

曲线轮廓字库,这是通过直线和曲线段共同构造文字的方法,往往使用Bezier曲线对轮廓进行拟合,效果非常好,字体平滑美工,但惟独就是计算较为费时间。

TrueType字形技术

TrueType采用几何学中二次B样条曲线及直线来描述字体的外形轮廓。由一些数学算法进行对应大小字体的生成,无论放大或缩小,字符总是光滑的。

TrueType字体与PostScript字体、OpenType字体是主要的三种计算机矢量字体(又称轮廓字体、描边字体),后缀.ttf。

虽然计算较快,但相比于PostScript字体,质量要差一些,特别是文字太小时,不够清晰。

所以字库一般会对小字体和常用打印字号制作对应的点阵字库,保证其精度,其他情况则使用TrueType字体。

WOFF–WebOpen Font Format (.woff)

WOFF(Web开发字体格式)是一种专门为了Web而设计的字体格式标准,实际上是对于TrueType/OpenType等字体格式的封装,每个字体文件中含有字体以及针对字体的元数据(Metadata),字体文件被压缩,以便于网络传输。

其实大家就会发现了,网络上很火的图标字体,实际上就是根据最基础的字库技术生成出来的。

字体的显示流程

介绍到这里,大家应该对整个字体的绘制过程有个整体的认识了,恩,首先是通过

首先是经过字符编解码,将硬盘中存储的有对应编码的文本文件进行加载,例如Java的文件IO,变成内存中的字符串对象,也就是符合本语言字符串存储特性的数据,(当然如果你愿意,也可以当做二进制读入,然后再手段转换编码,也是可以的),绘制时则首先调用对应的CodePage进行编码的索引查找,找到对应的字体字形索引,然后根据字形索引获取到字库中的数据,根据系统提供的绘制曲线绘制样条线的方法进行图形渲染,这样就能得到显示器上的图像了。而更高级的就是对字体进行反走样,锐化,等更为细节的操作了。

编码问题

编码问题解决起来实际上很简单,就是统一编码呗,所有需要注意的地方都有统一制定编码格式,这样,程序自然就会按照制定的编码进行操作。

Web页面编码

做网站时会用到大量的用户界面,这些用户界面的编码就是整个页面编码的核心,假若你用的是php,那么你肯定要在页面输出时,使用header函数,制定http返回的页面编码。

例如这样:

header("Content-type: text/html; charset=utf-8");

这样做的底层含义实际上是让html通信协议的报头指定了编码格式。

而拥有同样功能的meta标签

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

实际上也是让http协议发送时指定编码格式,防止乱码的方法。

资源文件编码

很多人认为指定了文件编码方式,就不会发送乱码了,真的是这样吗?显然不对,因为你要注意,你的html文件是怎么存的呢?假若你在用一个文本编辑器将html的内容保存成了gbk编码,虽然你在文本编辑器中是正常的,但由于你的文件存的编码和html指定的解码方式不统一,必然会导致乱码。

所以乱码问题必须时刻注意,文件的本身储存格式决定了其编码格式和声明的解码格式。而且更为让人难以捉摸的是,php的编码还有很多要注意的地方,比如php如果当做类代码来用时,php程序的编码并不是那么重要,但如果你在程序中定义中文字符串,或者将php当做模板引擎和html混排时,那php本身的编码和输出的编码都要注意,哪部分编码和解码的格式不符合,哪部分就会乱码。

而且使用php存取文件时尤为注意,资源文件的格式,是会影响编码的,如果你是按照字符串的方式存取还好说,但如果是用二进制存放时,则文本的编码是不会被自动转换的,所以要将这类资源文件的文件编码手动设置好。

数据库编码

数据库编码是十分重要的,我们在使用数据库时,往往会在创建数据库时,就指定好其默认的编码格式,以防乱码,但即使是这样,数据库往往也不会很听话的工作,因为有一个细节很难被注意到,那就是数据库SQL语句的编码。

例如:

<property name="url" value="jdbc:mysql://localhost:3306/email?useUnicode=true&characterEncoding=UTF-8" />

这样操作的最主要目的,就是不管数据库内部编码是什么样的,但字符串的编码格式在连接层会被统一,保证发过去的数据时utf-8的,返回时也是utf-8的,这样即使数据库本身存储编码不是utf-8,都不会有影响。

时间: 2024-11-03 01:33:39

网络编程中的编码问题汇总的相关文章

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模

用java网络编程中的TCP方式上传文本文件及出现的小问题

自己今天刚学java网络编程中的TCP传输,要用TCP传输文件时,自己也是遇到了一些问题,抽空把它整理了一下,供自己以后参考使用. 首先在这个程序中,我用一个客户端,一个服务端,从客户端上传一个文本文件给服务端,服务端接收数据并显示“上传成功”给客户端. 客户端: 1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.InputStr

linux网络编程中INADDR_ANY的使用

网络编程中常用到bind函数,需要绑定IP地址,这时可以设置INADDR_ANY INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”.“任意地址”. 也就是表示本机的所有IP,因为有些机子不止一块网卡,多网卡的情况下,这个就表示所有网卡ip地址的意思. 比如一台电脑有3块网卡,分别连接三个网络,那么这台电脑就有3个ip地址了,如果某个应用程序需要监听某 个端口,那他要监听哪个网卡地址的端口呢?如果绑定某个具体的ip地址,你只能监听你所设置的ip地

网络编程中的关键问题总结

总结下网络编程中关键的细节问题,包含连接建立.连接断开.消息到达.发送消息等等: 连接建立 包括服务端接受 (accept) 新连接和客户端成功发起 (connect) 连接. accept接受连接的问题在本文最后会聊到,这里谈谈connect的关键点:     使用非阻塞连接建立需要注意:     connect/select返回后,可能没有连接上:需要再次确认是否成功连接: 步骤为: 使用异步connect直接连接一次,因为使用了非阻塞,函数立刻返回: 检查返回值,为0成功连接,否则加入到s

网络编程中的同步与异步

网络编程中有三对关键的词,单线程与多线程.阻塞与非阻塞.同步与异步,同步与异步一直是比较疑惑的地方.以前认为,同步就是阻塞socket,异步就是非阻塞socket,现在发现这样理解很片面的,其实好多地方有同步异步的概念. 数字电路中的同步与异步是针对时钟来说的 同步时序逻辑电路:各触发器有相同的时钟脉冲,时钟脉冲到来时所有触发器状态同时改变异步时序逻辑电路:没有统一的时钟脉冲,所有触发器的状态转换不一定发生在同一时刻,某些触发器的状态转换有可能会延迟. 在通信原理中也有同步与异步的概念 同步传输

浅谈TCP/IP网络编程中socket的行为

我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉: . TCP/IP协议(如连接的建立和终止.重传和确认.滑动窗口和拥塞控制等等) . Socket I/O系统调用(重点如read/write),这是TCP/IP协议在应用层表现出来的行为. . 编写Performant, Scalable的服务器程序.包括多线程.IO Multiplexing.非阻塞.异步等各种技术. 关于TCP/IP协议,建议参考Richard Stevens的<TCP/IP Illust

网络编程中shut_down和close()函数的区别

在Linux C网络编程中,一共有两种方法来关闭一个已经连接好的网络通信,它们就是close函数和shutdown函数,它们的函数原型分别为: 1 #include<unistd.h> 2 int close(int sockfd) 3 //返回:0--成功, 1--失败 4   5 #include<sys/socket.h> 6 int shutdown(int sockfd, int howto) 7 //返回:0--成功, 1--失败 对一个tcp socket调用clos

socket编程之三:socket网络编程中的常用函数

这节本来打算先给出常用函数介绍,再给两个代码实例,写着写着发现越来越长,决定把代码放在下一节. 本节内容持续更新...... 1 socket()函数 原型: int socket(int domain, int type, int protocol); 描述: 类似打开一个文件,返回一个socket描述符,唯一标识一个socket,后面相应的操作都是这用这个socket描述符. 参数: domain:协议族,常用的协议族有AF_INET.AF_INET6.AF_LOCAL.AF_ROUTE等:

关于网络编程中MTU、TCP、UDP、IP

名词解释: MTU(Maxium Transmission Unit)最大传输单元 TCP (Transmission Control Protocal)传输控制协议 UDP (Usage Datagram Protocal)用户数据报协议 IP (Internet Protocal) 因特网协议 TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层(TCP/IP是一个协议簇,并不是代表TCP协议和IP协议) 以太网(Ethemet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传