《WebKit 技术内幕》学习之四(3): 资源加载和网络栈

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连接过程中涉及的类。

  • URLRequest类被上层调用并启动请求的时候,它会根据URL的“scheme”来决定需要创建什么类型的请求,“scheme”也就是URL的协议类型,如:“http://"、“file://”·,也可以是自定义的scheme,例如Andriod系统的”file://andriod_asset/“。URLRequest对象创建的是一个URLRequestJob子类的一个对象,例如图形的中的URLRequestHttpJob类。为了支持自定义的scheme处理方式,Chromium使用工厂模式。URLRequestJob类和它的工厂类URLRequestJobFactory的管理工作都由URLRequestJobManager类负责。基本思路是,用户可以在该类中注册多个工厂,当有URLRequest请求时,先由工厂检查它是否需要处理该类“scheme”,如果没有,工厂管理类继续交给下一个工厂类来处理。最后,如果没有任何工厂能够处理,Chromium则交给内置的工厂来检查和处理是否为“http://”、“f'tp://”或者“file://”等。
  • 当URLRequestHttpJob对象被创建后,该对象首先从Cookie管理器中获取与该URL相关的信息。之后,它同样借助于HttpTransactionFactory对象创建一个HttpTransaction对象来表示开启一个HTTP连接的事务(当然这里的概念不同于数据库中的事务概念)。通常情况下,HttpTransactionFactory对象对应的是一个它的子类HttpCache对象。HttpCache类使用本地磁盘缓存机制,如果该请求对应的回复已经在磁盘缓存中,那么Chromium无需再建立HttpTransaction来发起连接,而是直接从磁盘中获取即可。如果磁盘中没有该URL的缓存,同时如果目前该URL请求对应的HttpTransaction已经建立,那么只要等待它的回复即可。当这些条件都不满足的时候,Chromium实际上才会真正创建HttpTransaction对象、
  • HttpNetworkTransaction类使用HttpNetworkSession类来管理连接会话。HttpNetworkSession类通过它的成员HttpStreamFactory对象来建立TCPSocket连接,之后Chromium创建HttpStream对象。HttpStreamFactory对象将和网络之间的数据读写交给自己新创建的一个HttpStream子类的对象来处理。
  • 套接字的建立,Chromium中与服务器建立连接的套接字是StreamSocket类,它是一个抽象类,在POSIX系统和Windows系统上有着分别不同的实现。同时为了支持SSL机制,StreamSocket类还有一个子类----SSLSocket。

(3)代理

用户代理由以下几个类来处理:

  • Proxy Service:对于一个URL,HttpStreamFactory类使用ProxyService类来获取代理信息。ProxyService类首先会检查当前代理设置不是最新的。如果不是,它依赖ProxyConfigService来重新获取代理信息。该类不处理实际任务,而是使用ProxyReslover类来做实际代理工作。
  • Proxy Config Service:获取代理信息的类,可获得平台上的代理设置,在Linux】Windows上有不同的实现。
  • ProxyScriptFetcher:Chromium支持代理的JavaScript脚本,该类负责从代理的URL中获取该脚本。
  • Proxy Resolver:实际负责代理的解释和执行,通常启用新的线程来处理,因为当前可能会被域名的解析所阻碍。
  • ProxyResolverV8:ProxyResolver的子类,使用V8引擎来解析和执行脚本。

(4)域名解析(DNS)

        通常情况下,用户都是使用域名来访问网络资源的,所以在建立TCP连接前需要解析域名。Chromium中使用HostResolverImpl类来解析域名,具体调用的函数时“getaddrinfo()”,该函数是一个阻塞式的函数,所以Chromium理所当然使用单独的线程来处理它,这是Chromium的原则之一。

        为了保证效率,使用HostCache类来保存解析后的域名,最多时会有多达1000个域名和地址映射关系会被存储起来。

3,3 磁盘本地缓存

浏览器的缓存机制能够提高网页的加载速度。

(1)特性

  • 虽然需要缓存的资源可能很多,但磁盘空间不是无限大的,所以必须要有相应的机制来移除合适的缓存资源,以便加入新的资源。
  • 能够保证在浏览器崩溃时不破坏磁盘文件,至少能够保护原先在磁盘中的数据。
  • 能够高效和快速地访问磁盘中现有的数据结构,支持同步和异步两种访问方式。
  • 能够避免同时存储两个相同的资源。
  • 能够很方便地从磁盘中删除一个项,同时可以在操作一个项的时候不受其他请求的影响。
  • 磁盘不支持多线程访问,所以需要把所有磁盘缓存的操作放入单独的一个线程。
  • 升级版本时,如果磁盘缓存的内部存储结构发生改变,Chromium仍然能够支持老版本的结构。

(2)结构

        实现上主要有两个类,Backend(整个磁盘缓存) 和 Entry(表中的表项)。至少需要一个索引文件和四个数据文件。索引文件用来索引,数据文件又称块文件。缓存通常是一个表,对于整个表的操作作用在 Backend 类上,包括创建表中的一个个项,每个项由关键字来唯一个确定,这个关键字就是资源的 URL。对于项目内的操作包括读写都是由 Entry 类来处理。

  • Backend 类表示整个磁盘缓存,是所有磁盘缓存操作的主入口,表示一个缓存表。
  • 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.

        };

  • 数据文件:块文件,有很多不同大小的块,用于快速检索,这些数据块的内容是表项,包括 HTTP 文件头、请求数据和资源数据。资源文件大小超过一定值的时候,Chromium会捡来单独的文件来保存它们,而不是将它们放入四个数据文件中。这些单独存储的文件中并没有元数据信息,只是资源文件的内容,其文件名形如“f_xxxx,xxxx是0-9A-F是十六进制数来表示编号。

   表项的结构也分为两个部分:

  • 第一部分用于标记自己,包括各种元数据信息和自身的内容,较少变动
  • 第二部分主要为表项的回收算法服务,经常发生变动,里面保存了回收算法所需要的信息

     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的管理器,它包括几个作用:

  • 实现CookieStore的接口,它是对外的接口,调用者可以设置和获得Cookie。
  • 报告各种Cookie的事件,如更新信息等,主要使用Delegate类。
  • Cookie对象的集合,也就是CanonicalCookie的集合,每个CanonicalCookie对象表示一个域的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 预连接:

  • DNS 预取就是利用现有的 DNS 机制,提前解析网页中可能的网络连接。当用户正在浏览当前网页的时候,Chromium 提取网页中的超链接,将域名抽取出来,利用比较少的 CPU 和网络带宽来解析这些域名和 IP 地址,这样一来,用户根本感觉不到这一过程。当用户单击这些链接的时候,可以节省不少时间,特别在域名解析比较慢的时候,效果特别明显。
  • DNS预取技术直接利用系统的域名解析机制,不会阻碍当前网络栈的工作,DNS预取技术针对多个域名采取并行处理的方式,每个域名的解析须由新开启一个线程来处理,结束后此线程即退出。
  • 网页的开发者可以显示指定预取那些域名来让Chromium解析,这非常直接了当,特别对于那些需要重定向的域名,具体做法如下:<link rel="dns-prefetch" href="http://this-is-a-dns-prefetch-example.com">。当然,DNS预取技术不仅应用于网页中的超链接,在用户敲下回车键获取网页之前,Chromium 就已经开始用 DNS 预解析技术解析该域名。
  • 可以通过在地址栏中输入“chrome://dns/”查看Chromium的DNS预取的域名。
  • Chromium使用追踪技术来获取用户从什么网页跳转到另一个网页,可以利用这些数据、一些启发式规则和其他一些暗示来预测用户下面会单击什么超链接,当有足够的把握时,它便先DNS预取,更进一步,还可以预先建立TCP连接。
  • 同DNS预取技术一样,追踪技术不仅应用于网页中的超链接,当用户在地址栏输入地址,如候选项同输入的地址很匹配,则在用户敲下回车键获取该网页之前,Chromium就已经开始尝试建立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 的工作方式有以下四个特征:

  • 利用一个 TCP 连接来传输不限个数的资源请求的读写数据流。
  • 根据资源请求的特性和优先级, SPDY 可以调整这些资源请求的优先级。
  • 只对 https 请求使用压缩技术,可以大大减少需要传输的字节数。
  • 当用户需要浏览某个网页,支持 SPDY 的服务器在发送网页内容时可以发送一些信息给浏览器告诉后面可能需要哪些资源,浏览器可以提前知道并决定是否需要下载。更极端的情况是,服务器可以主动发送资源。

下图是是基于SPDY协议的网络栈结构

与前面的调用栈结构有三点不同:

  • 虚线框表示可能有多个SpdyStream和SpdyHttpStream对象,也就是多个流使用一个SpdySession会话,同时使用一个socket连接。多多个Stream对象的管理、删除、创建、数量限制等都是由SpdySession来处理。
  • 对于之前的一些类,Spdy有专门的实现,因为需要支持新协议的关系。
  • SpdyHttpStream类继承自之前的HttpStream类会对应一个SpdyStream并将Spdy协议部分等实际工作交给SpdyStream类来做

(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 使用网络资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

西方企业在与中国的竞争中,无可避免地“效仿中国”

长期以来&#xff0c;在西方观察家的视野里&#xff0c;中国科技领域的成功突破主要归结于三大支柱&#xff1a;一是中国建立了完备的基础设施网络&#xff1b;二是大量创新型企业如雨后春笋般涌现&#xff0c;以惊人的速度追赶乃至超越美国硅谷的企业&#xff1b;三是这些创新…

wps word 文档里的空白空间太大了

wps word 文档里的空白空间太大了&#xff0c;如下图1 点击【页面】--->【页边距】&#xff0c;把左边、右边的页边距调为0厘米。如下图2 点击【视图】--->【显示比例】从75%改为页宽&#xff0c;页宽的意思是使页面的宽度与窗口的宽度一致。如下图3 图1

浪花 - 用户加入队伍

一、接口设计 1. 请求参数&#xff1a;TeamJoinRequest package com.example.usercenter.model.request;import lombok.Data; import java.io.Serializable;/*** 加入队伍请求参数封装类*/ Data public class TeamJoinRequest implements Serializable {private static final…

用Axure RP 9制作弹出框

制作流程 1.准备文本框 下拉列表 按钮 动态面板 如图 2.先把下拉列表放好 再放动态面板覆盖 3.点动态面板 进入界面 如图 4.给按钮添加交互 3个按钮一样的 如图 5.提交按钮添加交互 如图

linux安装python3.11

yum -y gcc install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel下载地址 https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tar.xz 上传python文件&#x…

Kafka(二)【文件存储机制 生产者】

目录 一、Kafka 文件存储机制 二、Kafka 生产者 1、生产者消息发送流程 1.1、发送原理 2、异步发送 API 2.1、普通异步发送 案例演示 2.2、带回调函数的异步发送 2.3、同步发送 API 3、生产者分区 3.1、分区的好处 3.2、生产者发送消息的分区策略 &#xff08;1&am…

基于springboot+vue的学科竞赛管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

12.常用统计分析方法——聚类分析

目录 基础知识 实操 层次聚类 划分聚类 方法一&#xff1a;K均值聚类&#xff08;最常见&#xff09; 方法二&#xff1a;基于中心点的划分&#xff08;PAM&#xff09; 避免不存在的类 基础知识 概念&#xff1a; 聚类分析是一种数据归约技术&#xff0c;旨在揭露一个…

Python基础之数据库操作

一、安装第三方库PyMySQL 1、在PyCharm中通过 【File】-【setting】-【Python Interpreter】搜索 PyMySQL进行安装 2、通过PyCharm中的 Terminal 命令行 输入: pip install PyMySQL 注&#xff1a;通过pip安装&#xff0c;可能会提示需要更新pip&#xff0c;这时可执行&#…

discuz论坛附件上传限制大小2MB

我遇到了这个问题&#xff0c;去修改了配置PHP.ini文件没有解决. 我把他变成2000M依旧没有用&#xff0c;然后我选择了用户组&#xff0c;附件部分。如图所示&#xff1a; 然后这个时候我还是没有好&#xff0c;我同事的却不限制大小了&#xff0c;我去清理缓存&#xff…

中文电码在历史关键时刻的作用

1. 中文电码&#xff1a;一段被遗忘的历史 中文电码是一种将汉字转换为电信号编码的方式&#xff0c;它的历史可以追溯到19世纪末。在当时&#xff0c;电报技术传入中国&#xff0c;为了实现汉字的电子传输&#xff0c;我国学者研究了一种将汉字转换为电码的方法。这种方法通过…

go语言(十七)----json

1、结构体转json package mainimport ("encoding/json""fmt" )type Movie struct{Title string json:"title"Year int json:"year"Price int json:"rmb"Actors []string json:"actors" }func main() {movie : Mo…

2024.1.23栈与队列总结篇

2024.1.23栈与队列总结篇 栈经典题目 栈在系统中的应用 如果还记得编译原理的话&#xff0c;编译器在词法分析的过程中处理括号、花括号等这个符号的逻辑&#xff0c;就是使用了栈这种数据结构。 再举个例子&#xff0c;linux系统中&#xff0c;cd这个进入目录的命令我们应该…

C#winform上位机开发学习笔记6-串口助手的断帧功能添加

1.功能描述 按照设定时间对接收数据进行断帧(换行) 应用于需要接收完整数据包的场景&#xff0c;例如下位机发送一包数据为1秒&#xff0c;每100ms发送一组数据 大部分用于接收十六进制数据时 2.代码部分 步骤1&#xff1a;添加计时器&#xff0c;设置默认时间为500ms 步骤…

Lingo数学建模基础

1.基本运算符 1.1算数运算符 1.2逻辑运算 #not# 否定操作数的逻辑值&#xff0c;一元运算符 #eq# 若两运算数相等&#xff0c;则为true,否则为false #ne# 若两运算数不相等&#xff0c;则为true,否则为false #gt# 若左边运算数严格大于右边&#xff0c;则为true,否则为…

了解云工作负载保护:技术和最佳实践

云工作负载是指云环境中的应用程序或存储元素&#xff0c;无论是公共云、私有云还是混合云。每个云工作负载都使用云的资源&#xff0c;包括计算、网络和存储。 云工作负载可以多种多样&#xff0c;例如运行应用程序、数据库或托管网站。它们可以是静态的或动态的&#xff0c;…

代码随想录刷题题Day41

刷题的第四十一天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day41 任务 ● 583. 两个字符串的删除操作 ● 72. 编辑距离 ● 编辑距离总结篇 1 两个字符串的删除操作 583. 两个字符串的删除…

UI自动化定位元素之js操作

前言 在UI自动化测试中&#xff0c;元素定位是一个至关重要的步骤。准确地定位到页面上的元素&#xff0c;是实现自动化测试的前提和保障。本文将介绍使用JavaScript进行元素定位的常见方法&#xff0c;并分析页面的组成&#xff0c;帮助读者更好地理解和应用元素定位技术。 页…

MongoDB系列之一文总结索引

概述 分类 索引的分类&#xff1a; 按照索引包含的字段数量&#xff0c;可分为单键索引&#xff08;单字段索引&#xff09;和组合索引&#xff08;联合索引、复合索引&#xff09;按照索引字段的类型&#xff0c;可以分为主键索引和非主键索引按照索引节点与物理记录的对应…

NQA网络质量分析

概念 网络质量分析是设备上集成网络测试功能,不仅可以实现对网络运行情况的准确测试,还可以输出统计信息,有效的节约成本。 NQA可以检测网络上运行的各种协议的性能,使运营商能够实时采集到各种网络运行指标。 例如:HTTP的总时延、TCP连接时延、DNS解析时延、文件传输速…