Jack Jiang

我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
posts - 422, comments - 13, trackbacks - 0, articles - 0

     摘要: 本文由得物技术WWQ分享,原题“客服发送一条消息背后的技术和思”,本文有修订和改动。1、引言在企业IM客服场景中,客服发送一条消息的背后,需要考虑网络通信、前端展示、后端存储以及安全性等多个方面的技术支持。单从前端层面来说,就需要考虑到消息的显示、状态更新、稳定传输以及极限操作消息不卡顿等场景。随着IM系统的不断更新迭代,已经实现了从外采到自研再到一站式全场景工作台的搭建,...  阅读全文

posted @ 2023-11-02 11:02 Jack Jiang 阅读(84) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于Netty编写。

工程开源地址是:


关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► iOS端更新记录:http://www.52im.net/thread-2735-1-1.html
► 全部运行截图:iOS端全部运行截图 (另:Android端运行截图 点此查看
► 在线体验下载:App Store安装地址 (另:Android端下载体验 点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架 MobileIMSDK 实现)。


v8.0 版更新内容

此版更新内容更多历史更新日志):

  • 1)[新增] 新增了“群名片”功能;
  • 2)[新增] 新增了消息转发功能;
  • 3)[新增] 安全提升,启用了AppKey校验机制;
  • 4)[优化] 安全提升,优化了http接口、文件上传接口、socket长连接的token校验逻辑;
  • 5)[优化] 更换了新的高德地图websevice key;
  • 6)[优化] 其它ui细节和bug优化等。

此版新增功能运行截图(更多截图点此查看):

posted @ 2023-11-01 11:46 Jack Jiang 阅读(46) | 评论 (0)编辑 收藏

     摘要: 本文由序员先生分享,原题“技术解读企业微信之四维关系链”,本文有修订和改动。1、引言3年疫情后的中国社会,最大的永久性变化之一,就是大多数的企业、教育机构或者政务机构,都用上了综合性的SaaS在线办公系统。而这其中,企业微信的覆盖率非常高,而且其占比还在不断增长。越来越多的人因此好奇,开始想要更深度的了解企业微信,自然也就有越来越多的人开始解读企业微信。而解读的角度,五花八...  阅读全文

posted @ 2023-10-26 10:36 Jack Jiang 阅读(69) | 评论 (0)编辑 收藏

     摘要: 本文由大淘宝终端平台技术团队沈良炜(沛轩)分享,本文有修订和改动。1、引言自 2013 年 ALLIN 无线到今天,已经走过 10 个年头,淘宝终端统一网络库 AWCN (Ali Wireless Connection Network) 从淘内孵化,一路过来伴随着淘宝业务的发展,经历集团 IPv6 战役、协议升级演进等,逐步沉淀为阿里集团终端网络通用解决方案,是兼具高性能、多协议、可容灾、可观测的...  阅读全文

posted @ 2023-10-19 14:10 Jack Jiang 阅读(97) | 评论 (0)编辑 收藏

本文由百度技术王伟分享,原题“视频中为什么需要这么多的颜色空间?”,本文收录时有修订和改动。

1、引言

在视频处理中,我们经常会用到不同的色彩空间:非线性RGB,线性 RGB,YUV,XYZ……为什么需要这么多的色彩空间呢?为什么在 FFMpeg 中会有 color_space,color_transfer,color_primaries 等一系列的颜色属性呢?这些术语之间究竟隐藏着什么秘密?

本文将以通俗易懂的文字,引导你理解视频是如何从采集开始,历经各种步骤,最终通过颜色模型转换和不同的色域转换,让你看到赏心悦目的视频结果的。

 
 
技术交流:

(本文已同步发布于:http://www.52im.net/thread-4467-1-1.html

2、系列文章

本文是系列文章中的第20篇,本系列文章的大纲如下:

即时通讯音视频开发(一):视频编解码之理论概述

即时通讯音视频开发(二):视频编解码之数字视频介绍

即时通讯音视频开发(三):视频编解码之编码基础

即时通讯音视频开发(四):视频编解码之预测技术介绍

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(六):如何开始音频编解码技术的学习

即时通讯音视频开发(七):音频基础及编码原理入门

即时通讯音视频开发(八):常见的实时语音通讯编码标准

即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述

即时通讯音视频开发(十):实时语音通讯的回音消除技术详解

即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解

即时通讯音视频开发(十二):多人实时音视频聊天架构探讨

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十四):实时音视频数据传输协议介绍

即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况

即时通讯音视频开发(十六):移动端实时音视频开发的几个建议

即时通讯音视频开发(十七):视频编码H.264、V8的前世今生

即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门

即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换》(* 本文

3、视频采集

如上图所示,在相机系统中,外部世界的光信息(光子,photons)通过透镜或其他光学器件聚焦之后达到相机的图像传感器(CCD 或者 CMOS)。

过程是这样的:

  • 1)图像传感器可以将一个入射光子(photon)转换为对应的一个电子(electron);
  • 2)在曝光时间内,图像传感器对转换的电子进行电荷积累;
  • 3)然后,图像传感器会将积累的电荷信号转换成对应的电压信号;
  • 4)最后,利用 ADC 把电信号转换成数字信号,而转换后的数字信号则为某个范围内的整数值。

ADC 数字信号的取值范围 :

[pquote]ADC 转换之后的数字信号的取值范围受限于 ADC 设备。对于 8-bits 的 ADC 而言,数字信号的取值范围为 [0, 2^8-1],因此,对于每一个像素而言,会用 [0, 255] 之间的整数来进行编码。[/pquote]

ADC 转换的数字信号的数值是一个线性编码的过程,这意味着如果将图像传感器上的光量增加 1 倍,则 ADC 转换之后对应的数值也会增加 1 倍。

这是一个非常有用的特性:无论是增加物理世界的光量,还是增加 ADC 转换之后的数值,对图片而言,都会带来相同的效果。线性编码意味着我们所处理的数据和光发射的强度成正比关系。

由数码相机中的 CMOS 传感器产生并写入原始文件(Raw File)的数据是线性的。与普通照片相比,线性数据通常看起来非常暗且对比度较低。

在 iPhone 手机中,可以通过设置相机来拍摄 Apple ProRAW 格式的照片。

4、探索视频伽马校正

研究表明:人类视觉系统是以对数函数的方式来感知光亮度。这意味着:人眼会提高暗部的敏感度,降低高光部分的敏感度。

从数学角度看,感知光强度和测量光强度之间存在一个*似的*方关系,具体如下式所示。

由于人类视觉感知系统不是以线性方式工作的,因此必须使用非线性曲线来对 ADC 生成的的线性数据进行变换,从而使得拍摄的图像色调与我们的视觉系统的工作方式相匹配。这个过程也就是我们所说的 伽马校正。

因此:在从线性 RGB 空间转换到非线性 RGB 空间时,需要 γ 作为转换参数。相机中的 ISP 模块负责对图像传感器的线性 RGB 进行伽马校正进而产生对应的符合人眼感知的非线性 RGB 数据。

RGB 的设备依赖性 :

不同显示设备支持的色域空间不同,因此对于不同的显示设备而言,伽马校正之后的 RGB 数值也不同。从这个角度讲,RGB 是设备依赖型的色彩空间。

5、视频压缩

根据如上的信息,我们知道:相机系统经过 ISP 处理之后,最终会得到非线性的 RGB 信息。对于视频而言,如果以 RGB 存储每帧的信息,则需要消耗大量的存储空间。

人类视觉系统对颜色信息的敏感度要弱于亮度信息。利用这一特点,通常相机会将捕获的 RGB 信息转换为 YUV 格式,然后对 YUV 格式进行色度信息采样(例如,YUV420)以便压缩图像空间。

RGB->YUV,不同标准有不同要求,一般常用的标准有:

  • 1)BT. 601(SD: Standard-Definition);
  • 2)BT. 709(HD: High-Definition);
  • 3)BT. 2020(UHD: Ultra-High-Definition)。

注意 :

标准中,不但会规定 RGB->YUV 的转换系数,同时还会规定从线性 RGB 到非线性 RGB 转换的 gamma 系数。

将 RGB颜色模型,转换成 YUV 模型后,接下来会采用某种视频编解码算法(例如,H265, VP9)对获取的数据进行视频编码,最终得到视频文件(此处忽略了音频的采集编码以及合流的操作)。

6、视频转码

出于各种原因,例如:

  • 1)终端用户的带宽受限;
  • 2)终端用户支持的视频编解码算法和相机压缩视频的编解码算法不一致;
  • 3)……

一般不会直接把相机产出的视频文件分发给用户去消费。媒体服务商会对相机生成的视频文件进行转码,然后选择合适的转码后的视频分发给终端消费用户。

在视频转码阶段,如果我们希望对原视频进行色域的变换,例如从 BT. 601 转码为 BT. 709,则需要在不同色域的 RGB 数值之间进行转换。

在不同的色域空间进行 RGB 数据的转换,这也就是我们所说的 色彩管理。色彩管理会对图像进行色彩管理以适配当前环境下的颜色效果,从而保证同一张图片在不同输入、输出上都呈现出最好的颜色。

色彩转换需要在某个线性空间下进行操作,并且操作过程需要保持设备的独立性。因此,不同的 RGB 色域空间是不能直接进行转换的,需要一个设备无关、线性的颜色模型作为中转才能实现其转换。

而 XYZ(CIE 1931 XYZ color space)具备设备无关、线性操作的特性。

在 FFMpeg 中,主要使用 colorspace 滤镜 来完成不同色域空间的转换。

根据 colorspace 的实现可知,在 FFMpeg 中,BT. 601->BT. 709 的转换过程如下所示:

在如上的变换中,涉及到 3 个颜色空间的转换,分别是:

  • 1)YUV 和 RGB 之间的转换;
  • 2)线性 RGB 和非线性 RGB 之间的转换;
  • 3)线性 RGB 和 XYZ 之间的转换。

在 FFMpeg 中,所有的这些转换参数都保存在 AVFrame 结构中:

  • 1)AVFrame->colorspace 中保存了 YUV/RGB 的转换矩阵;
  • 2)AVFrame->color_trc 中保存了线性 RGB 和非线性 RGB 之间的转换函数(transformation characteristics);
  • 3)AVFrame->color_primaries 中保存了 RGB/XYZ 的转换矩阵;

如果用 ffprobe 命令解析视频文件,则:

  • 1)color_space 字段对应 YUV/RGB 的转换矩阵;
  • 2)color_transfer 字段对应线性 RGB 和非线性 RGB 之间的转换函数;
  • 3)color_primaries 字段对应 RGB/XYZ 的转换矩阵。

$ ffprobe -select_streams v:0 -show_entries stream=color_space,color_transfer,color_primaries test.mp4

 

[STREAM]

color_space=bt2020nc

color_transfer=arib-std-b67

color_primaries=bt2020

[/STREAM]

在如上的例子中,arib-std-b67 也就是我们所熟悉的 HLG。

在 MediaInfo 中:

  • 1)Matrix coefficients 字段对应 YUV/RGB 的转换矩阵;
  • 2)Transfer characteristic 字段对应线性 RGB 和非线性 RGB 之间的转换函数;
  • 3)Color primaries 字段对应 RGB/XYZ 的转换矩阵。

除了如上的参数外,AVFrame->range 还用来存储视频中对应像素的每个分量的取值范围。

在 vf_setparams.c 中也作了相关的定义说明:

{"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"tv",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"mpeg",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"full",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

{"pc",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

{"jpeg",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

7、视频解码&播放

7.1基本

转码之后的视频,可以通过各种渠道分发到终端用户进行消费。

对于大部分显示设备,例如CRT显示器、LCD、OLED,屏幕上的每个像素都是通过驱动三个非常靠*但仍然分开的小型 RGB 光源而构建的。

因此:显示屏(监视器、电视机、屏幕等等)仅使用 RGB 模型,并以不同的方式来组织,并显示最终的图像。

如前所述:不同的显示设备采用的 RGB 的色域并不一定相同,因此,RGB 是一种设备依赖型的颜色模型。在 Mac 电脑上,可以通过显示器配置来选择显示器支持不同的 RGB 色域。

7.2显示设备和相机的色域一致

如果编码视频和播放视频的显示器采用的 RGB 色域是一致的,比如都是 sRGB,此时的播放过程相对比较简单。

视频解码之后:得到 YUV 数据,然后根据标准将 YUV 数据转换成非线性的 sRGB 数据,然后显示器根据 sRGB 数据显示图像即可。

7.3显示设备和相机的色域不一致

当显示设备支持的色域从 sRGB 变为 Rec. 2020 时,如果直接显示 sRGB 色域下的数据,则会导致比较严重的颜色失真。

和转码阶段的色域转换类似,此时,也需要在不同的色域空间进行 RGB 数据的转换(色彩管理)以保证相同的视频在不同输入、输出、显示设备上都呈现出最好的颜色。

对于显示设备而言,sRGB->RGB(Rec. 2020)的转换过程如下所示:

因此:对于拍摄设备和显示设备的色域不同时,视频的播放增加了颜色管理的过程。

8、视频观看

虽然视频信息的采集和最终终端播放采用的都是 RGB 的颜色模型,但是对人眼而言,RGB 其实并不直观,比如我们很难马上反应出天青色的 RGB 色值?

为了能够更直观的表示颜色,又引入了 HSL 色彩模型。

HSL 比 RGB 更加直观,比如:想从黄色过度到红色,只需要调整色相即可,饱和度和亮度保持不变。因此,HSL 一般更适合人的色彩感知,而 RGB 更适合显示领域。

为了让作品可以呈现出期望的效果,提升用户的视觉体验,在摄影后期,使用 HSL 对作品进行调整是最方便的一种方式。利用 HSL 对作品进行调整,简单几步就可以让灰暗的「马路随拍」秒变「街头大片」。

FFMpeg 的 signalstats 滤镜可以分析获取视频的色调、饱和度、亮度信息。但是该滤镜获取的色调、饱和度和 HSL 中的计算 是不一致的。

signalstats 计算色调、饱和度的算法如下所示:

如果需要得到视频的标准 HSL 信息,可以使用作者开发的 vf_hsl 滤镜。

9、本文小结

虽然颜色还是那个颜色,但是不同的颜色空间的适用范围并不相同。

具体是:

  • 1)RGB:面向采集和显示设备;
  • 2)YUV:面向存储;
  • 3)HSL:面向人类视觉感知;
  • 4)XYZ:RGB之间的转换桥梁。

从视频采集到视频消费的整个过程,涉及到不同的设备和标准,而不同的设备和标准所支持的色域空间又不相同。

正是通过不同的颜色模型转换和不同的色域转换,才得以让我们实现:在不同输入、输出、显示设备上都呈现出最好的颜色,并以*似相同的观看体验来消费视频。

10、参考文献

[1] CMOS Image Sensor原理简述

[2] 数字视频导论

[3] 用HSL调色=简单、快速、超出片

[4] 零基础入门:实时音视频技术基础知识全面盘点

[5] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[6] 轻松诙谐,讲解视频编解码技术的过去、现在和将来

[7] 写给小白的实时音视频技术入门提纲

[8] 福利贴:最全实时音视频开发要用到的开源工程汇总

[9] 详解音频编解码的原理、演进和应用选型

[10] 零基础,史上最通俗视频编码技术入门


(本文已同步发布于:http://www.52im.net/thread-4467-1-1.html

posted @ 2023-10-12 11:20 Jack Jiang 阅读(52) | 评论 (0)编辑 收藏

一、更新内容简介

本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release NotesGithub Release Notes)。MobileIMSDK 可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。

二、MobileIMSDK简介

MobileIMSDK 是一套专为移动端开发的原创IM通信层框架:

  • 历经10年、久经考验;
  • 超轻量级、高度提炼,lib包50KB以内;
  • 精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准JavaH5小程序Uniapp
  • 服务端基于Netty,性能卓越、易于扩展;👈
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;👈
  • 可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

MobileIMSDK工程始于2013年10月,历经10年,起初用作某产品的即时通讯底层实现,完全从零开发,技术自主可控!

您可能需要:查看关于MobileIMSDK的详细介绍

三、源码托管同步更新

OsChina.net

GitHub.com

四、MobileIMSDK设计目标

让开发者专注于应用逻辑的开发,底层复杂的即时通讯算法交由SDK开发人员,从而解偶即时通讯应用开发的复杂性。

五、MobileIMSDK框架组成

整套MobileIMSDK框架由以下7部分组成:

  1. Android客户端SDK:用于Android版即时通讯客户端,支持Android 2.3及以上,查看API文档
  2. iOS客户端SDK:用于开发iOS版即时通讯客户端,支持iOS 9.0及以上,查看API文档
  3. Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,支持Java 1.6及以上,查看API文档
  4. H5客户端SDK查看精编注释版
  5. 微信小程序端SDK查看精编注释版
  6. Uniapp端SDK查看精编注释版
  7. 服务端SDK:用于开发即时通讯服务端,支持Java 1.7及以上版本,查看API文档

整套MobileIMSDK框架的架构组成:

 另外:MobileIMSDK可与姊妹工程 MobileIMSDK-Web 无缝互通,从而实现Web网页端聊天或推送等。

六、MobileIMSDK v6.4更新内容 

【重要说明】:

MobileIMSDK v6.4 为次要版本,进行了若干优化! 查看详情 (github

【新增重要特性】:

【解决的Bug】:

  • 1. [Uniapp端] 解决了Demo界面右上角的连接状态title无法更新的问题;
  • 2. [服务端] 解决桥接模式下与最新rabbitmq库不兼容从而断线重连不成功,导致MQ中消息堆积的问题。

【其它优化和提升】:

  • 1. [服务端] 解决登陆连接指令中的一处潜在空指针风险;
  • 2. [微信小程序端] 优化自带Demo中聊天主界面flex布局下的中部聊天列表高度自适应能力;
  • 3. [微信小程序端/H5端] 优化了Demo中的CSS代码;
  • 4. [微信小程序端/H5端] 优化了WebSocket的关闭逻辑,确保标准API中的close方法因异步调用带来socket实例被错误重置的问题;
  • 5. [H5端] 为Demo增加了消息送达状态图标的显示(包括发送中、发送成功、发送失败3种状态);
  • 6. [H5端] 重新设计了Demo的登录界面;
  • 7. [服务端] 升级amqp-client库至5.x版;
  • 8. [服务端] 解决桥接模式下MQ断线自动恢复时消费者Chennal未主动清理,导致channel越来越多的问题(无消费者与其关联的空channel):
  • 9. [Android] 提升targetSdkVersion至33(即Android 13);
  • 10. [Android] 升级开发工程使之支持最新Android Studio Giraffe和Gradle 8.1.1;

【最新版本源码地址】:

posted @ 2023-10-07 12:27 Jack Jiang 阅读(88) | 评论 (0)编辑 收藏

     摘要: 本文由字节教育-成人与创新前端团队分享,本文有修订和改动。1、引言作为开发人员,工作中我们可能会遇到以下问题:1)可能你知道 JavaScript 中 '😁'.length = 2,但 '👨👩👧👦'.length 呢?2)困惑于 Unicode 和 UTF-8 的关系?3)学计算机时会遇到这样的提问:一个汉字是几个字节?4)读取二进制数据时,为何有大端序小端序的分别?5)为何 UTF-8...  阅读全文

posted @ 2023-09-28 11:20 Jack Jiang 阅读(72) | 评论 (0)编辑 收藏

本文由阮一峰(ruanyifeng.com)分享,本文收录时有内容修订和排版优化。

1、引言

今天中午,我突然想搞清楚 Unicode 和 UTF-8 之间的关系,就开始查资料。

这个问题比我想象的复杂,午饭后一直看到晚上9点,才算初步搞清楚。

下面就是我的总结,主要用来整理自己的思路。我尽量写得通俗易懂,希望能对其他朋友有用。毕竟,字符编码是计算机技术的基石,对于程序员来说尤其重要,字符编码的知识是必须要懂的。

 
技术交流:

(本文已同步发布于:http://www.52im.net/thread-4433-1-1.html

2、专题目录

本文是“字符编码技术专题”系列文章的第 1 篇,总目录如下:

3、基础知识

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项*本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为*础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

4、ASCII 码

我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000到11111111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。

ASCII 码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0。

▲ ASCII编码表

5、非 ASCII 编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用 ASCII 码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

▲ 扩展ASCII编码表

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128--255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。

中文编码的问题比较复杂,将在文末讨论。这里先了解下,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的 Unicode 和 UTF-8 是毫无关系的。

6、Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字严。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

7、Unicode 的问题

需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字严的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。2)Unicode 在很长一段时间内无法推广,直到互联网的出现。

8、UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上*本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  • 1)对于单字节的符号:字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的;
  • 2)对于n字节的符号(n > 1):第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位:

跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

下面,还是以汉字严为例,演示如何实现 UTF-8 编码。

严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。

9、Unicode 与 UTF-8 之间的转换

通过上一节的例子,可以看到严的 Unicode码 是4E25,UTF-8 编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

Windows平台,有一个最简单的转化方法,就是使用内置的记事本小程序notepad.exe。打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条。

里面有四个选项:ANSI,Unicode,Unicode big endian和UTF-8

  • 1)ANSI是默认的编码方式:对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对 Windows 简体中文版,如果是繁体中文版会采用 Big5 码);
  • 2)Unicode编码这里指的是notepad.exe使用的 UCS-2 编码方式:即直接用两个字节存入字符的 Unicode 码,这个选项用的 little endian 格式;
  • 3)Unicode big endian编码与上一个选项相对应:我在下一节会解释 little endian 和 big endian 的涵义;
  • 4)UTF-8编码:也就是上一节谈到的编码方法。

选择完"编码方式"后,点击"保存"按钮,文件的编码方式就立刻转换好了。

10、Little endian 和 Big endian

上一节已经提到,UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字严为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,这就是 Big endian 方式;25在前,4E在后,这是 Little endian 方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

第一个字节在前,就是"大头方式"(Big endian),第二个字节在前就是"小头方式"(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

11、实例讲解

下面,举一个实例。

打开"记事本"程序notepad.exe,新建一个文本文件,内容就是一个严字,依次采用ANSI,Unicode,Unicode big endian和UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit 中的"十六进制功能",观察该文件的内部编码方式:

  • 1)ANSI:文件的编码就是两个字节D1 CF,这正是严的 GB2312 编码,这也暗示 GB2312 是采用大头方式存储的。
  • 2)Unicode:编码是四个字节FF FE 25 4E,其中FF FE表明是小头方式存储,真正的编码是4E25。
  • 3)Unicode big endian:编码是四个字节FE FF 4E 25,其中FE FF表明是大头方式存储。
  • 4)UTF-8:编码是六个字节EF BB BF E4 B8 A5,前三个字节EF BB BF表示这是UTF-8编码,后三个E4B8A5就是严的具体编码,它的存储顺序与编码顺序是一致的。

UltraEdit下载地址请至官网:https://www.ultraedit.com/

▲ UltraEdit软件

12、最后简要看看中文字符集和编码

12.1GB系列字符集&编码

计算机发明之处及后面很长一段时间,只用应用于美国及西方一些发达国家,ASCII能够很好满足用户的需求。但是当天朝也有了计算机之后,为了显示中文,必须设计一套编码规则用于将汉字转换为计算机可以接受的数字系统的数。

天朝专家把那些127号之后的奇异符号们(即EASCII)取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

上述编码规则就是GB2312。GB2312或GB2312-80是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·*本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312的出现,*本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。下图是GB2312编码的开始部分(由于其非常庞大,只列举开始部分,具体可查看GB2312简体中文编码表)。

▲ GB2312编码表的开始部分

由于GB 2312-80只收录6763个汉字,有不少汉字,如部分在GB 2312-80推出以后才简化的汉字(如"啰"),部分人名用字(如中国前总理***的"*"字),台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。于是厂商微软利用GB 2312-80未使用的编码空间,收录GB 13000.1-93全部字符制定了GBK编码。根据微软资料,GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样),最早实现于Windows 95简体中文版。虽然GBK收录GB 13000.1-93的全部字符,但编码方式并不相同。GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为"技术规范指导性文件"。原始GB13000一直未被业界采用,后续国家标准GB18030技术上兼容GBK而非GB13000。

GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术 信息交换用汉字编码字符集 *本集的扩充》的修订版。与GB 2312-1980完全兼容,与GBK*本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。

GB 18030主要有以下特点:

  • 与UTF-8相同,采用多字节编码,每个字可以由1个、2个或4个字节组成;
  • 编码空间庞大,最多可定义161万个字符;
  • 支持中国国内少数民族的文字,不需要动用造字区;
  • 汉字收录范围包含繁体汉字以及日韩汉字。

▲ GB18030编码总体结构

本规格的初版使中华人民共和国信息产业部电子工业标准化研究所起草,由国家质量技术监督局于2000年3月17日发布。现行版本为国家质量监督检验总局和中国国家标准化管理委员会于2005年11月8日发布,2006年5月1日实施。此规格为在中国境内所有软件产品支持的强制规格。

12.2BIG5字符集&编码

Big5,又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录13,060个汉字。中文码分为内码及交换码两类,Big5属中文内码,知名的中文交换码有CCCII、CNS11643。Big5虽普及于台湾、香港与澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界标准。倚天中文系统、Windows等主要系统的字符集都是以Big5为*准,但厂商又各自增加不同的造字与造字区,派生成多种不同版本。2003年,Big5被收录到CNS11643中文标准交换码的附录当中,取得了较正式的地位。这个最新版本被称为Big5-2003。

Big5码是一套双字节字符集,使用了双八码存储方法,以两个字节来安放一个字。第一个字节称为"高位字节",第二个字节称为"低位字节"。"高位字节"使用了0x81-0xFE,"低位字节"使用了0x40-0x7E,及0xA1-0xFE。

有关Big5的更多技术细节读者可单独深入研究,本文就不赘述了。

13、本文小结

这些字符集和编码的关系很容易让程序员混淆,现在小结一下。

简单来说:Unicode、GBK和Big5码等就是编码的值(也就是术语“字符集”),而UTF-8、UTF-16、UTF32之类就是这个值的表现形式(即术语“编码格式”)。

另外:Unicode、GBK和Big5码等字符集是不兼容的,同一个汉字在这三个字符集里的码值是完全不一样的。如"汉"的Unicode值与gbk就是不一样的,假设Unicode为a040,GBK为b030。以UTF-8为例,UTF-8码完全只针对Unicode来组织的,如果GBK要转UTF-8必须先转Unicode码,再转UTF-8就OK了。

即GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:

1)GBK、GB2312 --先转--> Unicode --再转--> UTF8

2)UTF8 --先转--> Unicode --再转--> GBK、GB2312

附录:更多IM技术精华文章

[1] 新手入门一篇就够:从零开发移动端IM

[2] 零*础IM开发入门(一):什么是IM系统?

[3] 零*础IM开发入门(二):什么是IM系统的实时性?

[4] 零*础IM开发入门(三):什么是IM系统的可靠性?

[5] 零*础IM开发入门(四):什么是IM系统的消息时序一致性?

[6] 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

[7] 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

[8] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[9] 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

[10] 史上最通俗Netty框架入门长文:*本介绍、环境搭建、动手实战

[11] 强列建议将Protobuf作为你的即时通讯应用数据传输格式

[12] IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!

[13] 微信新一代通信安全解决方案:*于TLS1.3的MMTLS详解

[14] 探讨组合加密算法在IM中的应用

[15] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[16] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[17] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[18] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[19] IM群聊消息如此复杂,如何保证不丢不重?

[20] 零*础IM开发入门(四):什么是IM系统的消息时序一致性?

[21] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[22] 如何保证IM实时消息的“时序性”与“一致性”?

[23] 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化

[24] 微信的海量IM聊天消息序列号生成实践(算法原理篇)

[25] 社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

[26] 网易云信技术分享:IM中的万人群聊技术方案实践总结

[27] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[28] 融云IM技术分享:万人群聊消息投递方案的思考和实践

[29] 为何*于TCP协议的移动端IM仍然需要心跳保活机制?

[30] 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

[31] 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)

[32] 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

[33] 阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践

[34] 彻底搞懂TCP协议层的KeepAlive保活机制

[35] 深度解密钉钉即时消息服务DTIM的技术设计

[36] *于实践:一套百万消息量小规模IM系统技术要点总结

[37] 跟着源码学IM(十):*于Netty,搭建高性能IM集群(含技术思路+源码)

[38] 一套十万级TPS的IM综合消息系统的架构实践与思考


(本文已同步发布于:http://www.52im.net/thread-4433-1-1.html

posted @ 2023-09-27 10:36 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯WXG客户端开发工程师yecong分享,本文做了修订和改动。1、引言相对于传统的消费级IM应用,企业级IM应用的特殊之外在于它的用户关系是按照所属企业的组织架构来关联的起来,而组织架构的大小是无法预设上限的,这也要求企业级IM应用在遇到真正的超大规模组织架构时,如何保证它的应用性能不受限于(或者说是尽可能不受限于)企业架构规模,这是个比较有难度的技术问题。本文主要分享的是企业微信在百对百...  阅读全文

posted @ 2023-09-21 11:15 Jack Jiang 阅读(68) | 评论 (0)编辑 收藏

为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第21 期。

[- 1 -] 新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

[链接http://www.52im.net/thread-2007-1-1.html

[摘要] 本文我们就来聊聊分布式架构的演进过程,希望能给大家带来眼前一亮的感觉。


[- 2 -] 一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等

[链接http://www.52im.net/thread-2494-1-1.html

[摘要] 本文将从负载均衡技术的分类、技术原理、常见实现算法、常用方案等入手,为您详细讲解负载均衡技术的方方面面。这其中,四层和七层负载均衡技术最为常用,它们也是本文介绍的重点。


[- 3 -] 从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

[链接http://www.52im.net/thread-2665-1-1.html

[摘要] 本文以设计淘宝网的后台架构为例,介绍从一百个并发到千万级并发情况下服务端的架构的14次演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知。


[- 4 -] 腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

[链接http://www.52im.net/thread-1811-1-1.html

[摘要] 本文结合作者多年的互联网系统设计实践经验,从最基本的技术概念开始,带你探寻服务器端系统架构的方方面面。


[- 5 -] 快速理解高性能HTTP服务端的负载均衡技术原理

[链接http://www.52im.net/thread-1950-1-1.html

[摘要] 本文将以简洁通俗的文字,为你讲解主流的HTTP服务端实现负载均衡的常见方案,以及具体到方案中的负载均衡算法的实现原理。理解和掌握这些方案、算法原理,有助于您今后的互联网项的技术选型和架构设计,因为没有哪一种方案和算法能解决所有问题,只有针对特定的场景使用合适的方案和算法才是最明智的选择。


[- 6 -] 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

[链接http://www.52im.net/thread-1968-1-1.html

[摘要] 本文作者陈鹏是该系统的负责人,本次文章深入介绍了该系统的方方面面,值得互联网后端程序员仔细研究。


[- 7 -] 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

[链接http://www.52im.net/thread-2050-1-1.html

[摘要] 阿里数据库事业部研究员张瑞,将为你讲述双11数据库技术不为人知的故事。在零点交易数字一次次提升的背后,既是数据库技术的一次次突破,也见证了阿里技术人永不言败的精神,每一次化“不可能”为“可能”的过程都是阿里技术人对技术的不懈追求。


[- 8 -]  阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

[链接http://www.52im.net/thread-2072-1-1.html

[摘要] OceanBase 是蚂蚁金服自研的分布式数据库,在其 9 年的发展历程里,从艰难上线到找不到业务场景濒临解散,最后在双十一的流量考验下浴火重生,成为蚂蚁金服全部核心系统的承载数据库。这一路走来的艰辛和故事,蚂蚁金服高级研究员、OceanBase 团队负责人阳振坤将为你娓娓道来。


[- 9 -] 达达O2O后台架构演进实践:从0到4000高并发请求背后的努力

[链接http://www.52im.net/thread-2141-1-1.html

[摘要] 达达的业务组成简单直接——商家下单、配送员接单和配送,也正因为理解起来简单,使得达达的业务量在短时间能实现爆发式增长。而支撑业务快速增长的背后,正是达达技术团队持续不断的快速技术迭代的结果,本文正好借此机会,总结并分享了这一系列技术演进的第一手实践资料,希望能给同样奋斗在互联网创业一线的你带来启发。


[- 10 -] 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结

[链接http://www.52im.net/thread-2157-1-1.html

[摘要] 本文将总结和分享当MySQL单表记录数过大时,增删改查性能急剧下降问题的优化思路,这也是资深后端架构师、程序员所必备的知识内容之一,希望本文对你有用。


[- 11 -] 通俗易懂:如何设计能支撑百万并发的数据库架构?

[链接http://www.52im.net/thread-2510-1-1.html

[摘要] 本篇文章我们一起来学习一下,对于一个支撑日活百万用户的高并发系统,数据库架构应该如何设计呢?


[- 12 -] 多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

[链接http://www.52im.net/thread-2625-1-1.html

[摘要] 本文将从17个维度综合对比Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ这5款当前最主流的MQ消息中间件产品,希望能为您的下一次产品的架构设计和MQ消息中间件选型提供参考依据。


[- 13 -] 小米技术分享:解密小米抢购系统千万高并发架构的演进和实践

[链接http://www.52im.net/thread-2323-1-1.html

[摘要] 本次分享将为大家解密该系统的技术演进、设计思路、实践总结等,希望能带给您启发。


[- 14 -] 美团技术分享:深度解密美团的分布式ID生成算法

[链接http://www.52im.net/thread-2751-1-1.html

[摘要] 对于美团的Leaf-segment这个ID生成方案,因为生成的ID全局唯一、全局有序,所以非常适合IM这种应用场景,这也是即时通讯网整理并分享给社区的原因。


[- 15 -] 12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统(含源码)

[链接http://www.52im.net/thread-2771-1-1.html

[摘要] 本文内容虽是从秒杀系统谈起,并未直接涉及即时通讯相关知识,但有关Go的高并发实践,仍然值得广大即时通讯网的技术爱好者们研究和学习,必竟业务可以不同,但技术都是相通的,或许能为你即时通讯系统的高并发架构带来新的思路和灵感。


👉52im社区本周新文:《企业微信针对百万级组织架构的客户端性能优化实践 http://www.52im.net/thread-4437-1-1.html》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2023-09-20 12:31 Jack Jiang 阅读(57) | 评论 (0)编辑 收藏

仅列出标题
共43页: 上一页 1 2 3 4 5 6 7 8 9 下一页 Last 
Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang