3. 网络栈
3.1 WebKit的网络设施
? ? ? ? WebKit的资源加载其实是交由各个移植来实现的,所以WebCore其实并没有什么特别的基础设施,每个移植的网络实现是非常不一样的。
? ? ? ? 从WebKit的代码结构中可以看出,网络部分代码的确比较少的,它们都在目录“WebKit/Source/WebCore/platform/network”中。主要是一些HTTP消息头、MIME消息、状态码等信息的描述和处理,没有实质的网络连接和各种针对网络的优化。
3.2 Chromium网络栈
(1)“net“所包含的主要子目录,是chromium网络栈的主要模块。要实现一些基础的部分,如 HTTP 协议、DNS 解析等模块,还包括一些为了减少网络时间而引入的新技术(如 SPDY、QUIC 等)。
(2)网络栈结构
????????在“Net”目录下的子目录,包含了主要的子模块,如下图描述了从URLRequest类到Socket类之间的调用过程。以HTTP协议为例,图中列出了建立TCP的Socket连接过程中涉及的类。
(3)代理
用户代理由以下几个类来处理:
(4)域名解析(DNS)
? ? ? ? 通常情况下,用户都是使用域名来访问网络资源的,所以在建立TCP连接前需要解析域名。Chromium中使用HostResolverImpl类来解析域名,具体调用的函数时“getaddrinfo()”,该函数是一个阻塞式的函数,所以Chromium理所当然使用单独的线程来处理它,这是Chromium的原则之一。
? ? ? ? 为了保证效率,使用HostCache类来保存解析后的域名,最多时会有多达1000个域名和地址映射关系会被存储起来。
3,3 磁盘本地缓存
浏览器的缓存机制能够提高网页的加载速度。
(1)特性
(2)结构
????????实现上主要有两个类,Backend(整个磁盘缓存) 和?Entry(表中的表项)。至少需要一个索引文件和四个数据文件。索引文件用来索引,数据文件又称块文件。缓存通常是一个表,对于整个表的操作作用在 Backend 类上,包括创建表中的一个个项,每个项由关键字来唯一个确定,这个关键字就是资源的 URL。对于项目内的操作包括读写都是由 Entry 类来处理。
????????表和表项如何组织和存储在磁盘上:至少有一个索引文件和四个数据文件(块文件),每个块文件的大小是固定的,当资源文件超过某个块的大小就会为其分配多个块来解决,但最多不能超过四个块,超过四个块能存储的时候会建立单独的文件来保存。如果一个表项需要分配四个块则这些块在文件中的索引位置是对齐的(起始块的位置是4 的倍数)
? ? ? ? struct NET_EXPORT_PRIVATEIndex Header{
? ? ? ? ? ? ? ? uint32? magic;
? ? ? ? ? ? ? ? uint32 version;
? ? ? ? ? ? ? ? int32 num_entries;? ? ?//nuimuber entries currently stored.
? ? ? ? ? ? ? ? int32 num_bytes;? ? ? ?//Total size of the stored data.
? ? ? ? ? ? ? ? int32 last_file;? ? ? ? ? ? ?//Last external file created.
? ? ? ? ? ? ? ? int32? this_id;? ? ? ? ? ? ? //Id for all entries being changed (dirty flag).
? ? ? ? ? ? ? ? CacheAddr status;? ? ? //Storage for usage data.
? ? ? ? ? ? ? ? int32? table_len;? ? ? ? ?//Actual size of the table(0==kIndexTablesize),
? ? ? ? ? ? ? ? int32? crash;? ? ? ? ? ? ? ? //Signals a previous crash.
? ? ? ? ? ? ? ? int32? experiment;? ? ? ?//Id of an ongoing test.
? ? ? ? ? ? ? ? uint64? ?create_time;? ?//Creation time for this set of files.
? ? ? ? ? ? ? ? int32? ?pad[52];
? ? ? ? ? ? ? ? LruData? lru;? ? ? ? ? ? ?//Eviction control data.
????????};
????????strunct? Index? {? ? ? ? ? ? ? ? ?// The structure of the whole index file.
? ? ????????? ? IndexHeader header;
? ? ????????? ? CacheAddr table[kIndexTablesize]?;? ?//Default size Actual size controlled by header.table_len.
????????};
? ?表项的结构也分为两个部分:
?????struct EntryStore {
? ? ? ? ? ? ? ? uint32? hash;? ? ? ? ? ? ? ? ? ? ? ? ? ?//Full hash of the key.
? ? ? ? ? ? ? ? CacheAddr? next;? ? ? ? ? ? ? ? ?//Next entry with the same hash or bucket.
? ? ? ? ? ? ? ? CacheAddr? rankings_node;? ?//Rankings node for this entry.
? ? ? ? ? ? ? ? int32? ?reuse_count;? ? ? ? ? ? ? ? //How often is this entry used.
? ? ? ? ? ? ? ? int32? refetch_count;? ? ? ? ? ? ? ?//How often is this fetched from the net.
? ? ? ? ? ? ? ? int32? state;? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//Current state
? ? ? ? ? ? ? ? uint64? creation_time;
? ? ? ? ? ? ? ? int32? ?key_len;
? ? ? ? ? ? ? ? CachedAddr? long_key;? ? ? ? ? ? ? ? ? ?//Optional adddress of a? long key.
? ? ? ? ? ? ? ? int32? ? ? ? ? ?data_size[4];? ? ? ? ? ? ? ? ? ?//We can store up to 4 data streams for each
? ? ? ? ? ? ? ? CacheAddr? data_add[4];? ? ? ? ? ? ? ? ?//entry
? ? ? ? ? ? ? ? uint32? ? ? flags;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //Any Combination of EntryFlags.
? ? ? ? ? ? ? ? int32? ?pad[4];
? ? ? ? ? ? ? ? uint32? ? self_hash;? ? ? ? ? ? ? ? ? ? ? ? ? ?// The hash of EntryStore up to this point.
? ? ? ? ? ? ? ? char? ?key[256-24*4];? ? ? ? ? ? ? ? ? ? ? ? //null terminated
? ? ? ? };
磁盘缓存的存储结构如下:
????????Chomium使用LRU算法来回收表项,因为磁盘存储的空间是有限的,不能无限的增长下去,所以对于很少使用到的表项,可以回收这一部分磁盘空间。
3.4? Cookie机制
? ? ? ? Cookie就是一系列的“关键字+值”对。
? ? ? ? test1=webkit;test2=chromium;Expires=Sun,30 Oct 2016 21:35:00 GMT;Domain.myweb.com;
? ? ? ? test1,test2 自定义的关键字
? ? ? ? Expires、Domain:为预定义的关键字,表示的是该Cookie的失效时间和该Cookie对应的域。
????????一个网页的 Cookie 只能被该网页(或者说是该域的网页)访问。根据 Cookie 的时效性可以将 Cookie 分成两种类型,第一种是会话型 Cookie(Session Cookie),这些 Cookie 只是保存在内存中,当浏览器退出的时候即清除这些 Cookie。如果 Cookie 没有设置失效时间,就是会话型 Cookie。第二中是持续型 Cookie(Persistent Cookie),也就是当浏览器退出的时候,仍然保留 Cookie 的内容。该类型的 Cookie 有一个有效期,在有效期内,每次访问该 Cookie 所属域的时候,都需要将该 Cookie 发送个服务器,这样服务器就能够追踪用户的行为。
? ? ? ? Chromium中支持Cookie的机制也较为简单和清晰,CookieMonster是Cookie机制中最重要的类,实际上相当于Cookie的管理器,它包括几个作用:
????????以上的是在内存中保存的,当需要存储到磁盘的时候使用PersistentCookieStore,具体由SQLLitePersistenCookieStore类负责实际的存储动作。
3.5? 安全机制
????????HTTP是一种使用明文来传输数据的应用层协议。构建建在SSL之上的HTTPS提供了安全的网络传输机制。支持一种新的标准 HSTS 协议(HTTP Strict Transport Security):能够让网络服务器声明它只支持 HTTPS 协议。浏览器能够理解服务器的声明,发送基于 HTTPS 的连接和请求。通常情况下,浏览器的用户不会输入“scheme(http://),l浏览器的补齐功能通常会加入该“scheme”,但是,服务器可能需要”https://",在这样的情况下,该协议就显得非常有用。一般情况次啊,服务在返回的消息头中加入以下信息表明它支持该标准。
????????Strict-Transport-Security:max-age=16070400;includesSubDomains
3.6? 高性能网络栈
? ? ? ? Chromium的网络模块有两个重要目标,其一是安全,其二是速度。
(1)DNS 预取和 TCP 预连接:
(2)支持 HTTP 管线化技术(Pipelining):
????????HTTP 1.1 中新增的管线化技术:将多个 HTTP 请求一次性提交给服务器,可能将多个 HTTP 请求填充在 TCP 数据包内(相当于 HTTP 权威指南中串行事务处理中的管道化连接),HTTP管线化需要在网络上传较少的TCP数据包,因此减少了网络的负载。
? ? ? ? 请求结果的管线化使得HTML网页加载时间动态提升,特别在具体有高延迟的连接环境下,管线化机制需要通过永久连接(Persistent Connection)完成,并且只有 GET 和 HEAD 等幂等请求可以进行管线化。使用场景有很大的限制。
(3)? SPDY
????????解决 HTTP 管线技术的使用限制。SPDY 协议是一种新的会话层协议,定义在 HTTP 协议和 TCP 协议之间。核心思想是多路复用,仅使用一个连接来传输一个网页中的众多资源,没有改变 HTTP 协议,将 HTTP 协议头通过 SPDY 来封装和传输,服务器只需要从 SPDY 的消息头中获取各个资源的 HTTP 头即可。SPDY 的工作方式有以下四个特征:
下图是是基于SPDY协议的网络栈结构
与前面的调用栈结构有三点不同:
(4)QUIC
????????新的网络传输协议,改进 UDP 数据协议的能力。同SPDY建立传输层之上不同,QUIC所要解决的问题就是传输层的传输效率,并提供了数据加密。所以,SPDY可以在QUIC上工作。
3.7 实践:chromium网络工具和信息
? ? ?Chromium提供了网路信息工具Chrome://net-internals.可以看到Capture、Export、Import、Proxy、Events、Timeline、DNS、Sockets、SPDY、QUIC、Pipelining、擦车、SPIs、Tests、HSTS、Bandwidth、Prerender等类别。
? ? ? ? 首先是Events类别,该类别记录了所有网络栈完成的工作和传送消息。记录ID、对象类。其中有些以_JOB结尾的类,表示一个个的任务,这些任务可能是连接、域名解析等。它们不负责具体的工作,只起到一层桥接和封装的作用,任务完成后就直接结束了,当用户单击表中一项的时候,当前页面会给当前对象从过去到现在发生的各个操作,或者叫事件。
????????其次是类别“Timeline”.它的含义就是一个按照时间绘制的图,图中记录在各个时间点Chromium 使用网络资源。