本文转载自:https://github.com/skyline75489/what-happens-when-zh_CN#id9css
接下来的内容介绍了物理键盘和系统中断的工做原理,可是有一部份内容却没有涉及。当你按下“g”键,浏览器接收到这个消息以后,会触发自动完成机 制。浏览器根据本身的算法,以及你是否处于隐私浏览模式,会在浏览器的地址框下方给出输入建议。大部分算法会优先考虑根据你的搜索历史和书签等内容给出建 议。你打算输入 "google.com",所以给出的建议并不匹配。可是输入过程当中仍然有大量的代码在后台运行,你的每一次按键都会使得给出的建议更加准确。甚至有可能 在你输入以前,浏览器就将 "google.com" 建议给你。html
为了从零开始,咱们选择键盘上的回车键被按到最低处做为起点。在这个时刻,一个专用于回车键的电流回路被直接地或者经过电容器间接地闭合了,使得少 量的电流进入了键盘的逻辑电路系统。这个系统会扫描每一个键的状态,对于按键开关的电位弹跳变化进行噪音消除(debounce),并将其转化为键盘码值。 在这里,回车的码值是13。键盘控制器在获得码值以后,将其编码,用于以后的传输。如今这个传输过程几乎都是经过通用串行总线(USB)或者蓝牙 (Bluetooth)来进行的,之前是经过PS/2或者ADB链接进行。node
USB键盘:linux
虚拟键盘(触屏设备):nginx
键盘在它的中断请求线(IRQ)上发送信号,信号会被中断控制器映射到一个中断向量,实际上就是一个整型数 。CPU使用中断描述符表(IDT)把中断向量映射到对应函数,这些函数被称为中断处理器,它们由操做系统内核提供。当一个中断到达时,CPU根据IDT 和中断向量索引到对应的中断处理器,而后操做系统内核出场了。git
WM_KEYDOWN
消息被发往应用程序HID把键盘按下的事件传送给 KBDHID.sys
驱动,把HID的信号转换成一个扫描码(Scancode),这里回车的扫描码是 VK_RETURN(0x0d)
。 KBDHID.sys
驱动和 KBDCLASS.sys
(键盘类驱动,keyboard class driver)进行交互,这个驱动负责安全地处理全部键盘和小键盘的输入事件。以后它又去调用 Win32K.sys
,在这以前有可能把消息传递给安装的第三方键盘过滤器。这些都是发生在内核模式。github
Win32K.sys
经过 GetForegroundWindow()
API函数找到当前哪一个窗口是活跃的。这个API函数提供了当前浏览器的地址栏的句柄。Windows系统的"message pump"机制调用 SendMessage(hWnd, WM_KEYDOWN, VK_RETURN, lParam)
函数, lParam
是一个用来指示这个按键的更多信息的掩码,这些信息包括按键重复次数(这里是0),实际扫描码(可能依赖于OEM厂商,不过一般不会是 VK_RETURN
),功能键(alt, shift, ctrl)是否被按下(在这里没有),以及一些其余状态。算法
Windows的 SendMessage
API直接将消息添加到特定窗口句柄 hWnd
的消息队列中,以后赋给 hWnd
的主要消息处理函数 WindowProc
将会被调用,用于处理队列中的消息。windows
当前活跃的句柄 hWnd
其实是一个edit control控件,这种状况下,WindowProc
有一个用于处理 WM_KEYDOWN
消息的处理器,这段代码会查看 SendMessage
传入的第三个参数 wParam
,由于这个参数是 VK_RETURN
,因而它知道用户按下了回车键。后端
KeyDown
NSEvent被发往应用程序中断信号引起了I/O Kit Kext键盘驱动的中断处理事件,驱动把信号翻译成键码值,而后传给OS X的 WindowServer
进程。而后, WindowServer
将这个事件经过Mach端口分发给合适的(活跃的,或者正在监听的)应用程序,这个信号会被放到应用程序的消息队列里。队列中的消息能够被拥有足够高权限的线程使用 mach_ipc_dispatch
函数读取到。这个过程一般是由 NSApplication
主事件循环产生而且处理的,经过 NSEventType
为 KeyDown
的 NSEvent
。
当使用图形化的 X Server 时,X Server 会按照特定的规则把键码值再一次映射,映射成扫描码。当这个映射过程完成以后, X Server 把这个按键字符发送给窗口管理器(DWM,metacity, i3等等),窗口管理器再把字符发送给当前窗口。当前窗口使用有关图形API把文字打印在输入框内。
浏览器经过 URL 可以知道下面的信息:
Protocol
"http"使用HTTP协议
Resource
"/"请求的资源是主页(index)
当协议或主机名不合法时,浏览器会将地址栏中输入的文字传给默认的搜索引擎。大部分状况下,在把文字传递给搜索引擎的时候,URL会带有特定的一串字符,用来告诉搜索引擎此次搜索来自这个特定浏览器。
a-z
, A-Z
,0-9
, -
或者 .
的字符google.com
,因此没有非ASCII的字符,若是有的话,浏览器会对主机名部分使用 Punycode 编码gethostbyname
库函数(操做系统不一样函数也不一样)进行查询gethostbyname
函数在试图进行DNS解析以前首先检查域名是否在本地 Hosts 里,Hosts 的位置 不一样的操做系统有所不一样gethostbyname
没有这个域名的缓存记录,也没有在 hosts
里找到,它将会向 DNS 服务器发送一条 DNS 查询请求。DNS 服务器是由网络通讯栈提供的,一般是本地路由器或者 ISP 的缓存 DNS 服务器。要想发送 ARP 广播,咱们须要有一个目标 IP 地址,同时还须要知道用于发送 ARP 广播的接口的 MAC 地址。
若是缓存没有命中:
ARP Request
:
Sender MAC: interface:mac:address:here Sender IP: interface.ip.goes.here Target MAC: FF:FF:FF:FF:FF:FF (Broadcast) Target IP: target.ip.goes.here
根据链接主机和路由器的硬件类型不一样,能够分为如下几种状况:
直连:
ARP Reply
(见下面)。集线器:
ARP Reply
。交换机:
ARP Reply
ARP Reply
:
Sender MAC: target:mac:address:here Sender IP: target.ip.goes.here Target MAC: interface:mac:address:here Target IP: interface.ip.goes.here
如今咱们有了 DNS 服务器或者默认网关的 IP 地址,咱们能够继续 DNS 请求了:
当浏览器获得了目标服务器的 IP 地址,以及 URL 中给出来端口号(http 协议默认端口号是 80, https 默认端口号是 443),它会调用系统库函数 socket
,请求一个 TCP流套接字,对应的参数是 AF_INET
和 SOCK_STREAM
。
到了如今,TCP 封包已经准备好了,可使用下面的方式进行传输:
对于大部分家庭网络和小型企业网络来讲,封包会从本地计算机出发,通过本地网络,再经过调制解调器把数字信号转换成模拟信号,使其适于在电话线路,有线电视光缆和无线电话线路上传输。在传输线路的另外一端,是另一个调制解调器,它把模拟信号转换回数字信号,交由下一个 网络节点 处理。节点的目标地址和源地址将在后面讨论。
大型企业和比较新的住宅一般使用光纤或直接以太网链接,这种状况下信号一直是数字的,会被直接传到下一个 网络节点 进行处理。
最终封包会到达管理本地子网的路由器。在那里出发,它会继续通过自治区域的边界路由器,其余自治区域,最终到达目标服务器。一路上通过的这些路由器 会从IP数据报头部里提取出目标地址,并将封包正确地路由到下一个目的地。IP数据报头部TTL域的值每通过一个路由器就减1,若是封包的TTL变为0, 或者路由器因为网络拥堵等缘由封包队列满了,那么这个包会被路由器丢弃。
上面的发送和接受过程在 TCP 链接期间会发生不少次:
客户端选择一个初始序列号(ISN),将设置了 SYN 位的封包发送给服务器端,代表本身要创建链接并设置了初始序列号
Client hello
消息到服务器端,消息中同时包含了它的TLS版本,可用的加密算法和压缩算法。Server hello
消息,消息中包含了服务器端的TLS版本,服务器选择了哪一个加密和压缩算法,以及服务器的公开证书,证书中包含了公钥。客户端会使用这个公钥加密接下来的握手过程,直到协商生成一个新的对称密钥Finished
消息给服务器端,使用对称密钥加密此次通信的一个散列值Finished
消息,也使用协商好的对称密钥加密若是浏览器是 Google 出品的,它不会使用 HTTP 协议来获取页面信息,而是会与服务器端发送请求,商讨使用 SPDY 协议。
若是浏览器使用 HTTP 协议,它会向服务器发送这样的一个请求:
GET / HTTP/1.1 Host: google.com [其余头部]
“其余头部”包含了一系列的由冒号分割开的键值对,它们的格式符合HTTP协议标准,它们之间由一个换行符分割开来。这里咱们假设浏览器没有违反HTTP协议标准的bug,同时浏览器使用 HTTP/1.1
协议,否则的话头部可能不包含 Host
字段,同时 GET
请求中的版本号会变成 HTTP/1.0
或者 HTTP/0.9
。
HTTP/1.1 定义了“关闭链接”的选项 "close",发送者使用这个选项指示此次链接在响应结束以后会断开:
Connection:close
不支持持久链接的 HTTP/1.1 必须在每条消息中都包含 "close" 选项。
在发送完这些请求和头部以后,浏览器发送一个换行符,表示要发送的内容已经结束了。
服务器端返回一个响应码,指示此次请求的状态,响应的形式是这样的:
200 OK [响应头部]
而后是一个换行,接下来有效载荷(payload),也就是 www.google.com
的HTML内容。服务器下面可能会关闭链接,若是客户端请求保持链接的话,服务器端会保持链接打开,以供之后的请求重用。
若是浏览器发送的HTTP头部包含了足够多的信息(例如包含了 Etag 头部,以致于服务器能够判断出,浏览器缓存的文件版本自从上次获取以后没有再更改过,服务器可能会返回这样的响应:
304 Not Modified [响应头部]
这个响应没有有效载荷,浏览器会从本身的缓存中取出想要的内容。
在解析完 HTM L以后,浏览器和客户端会重复上面的过程,直到HTML页面引入的全部资源(图片,CSS,favicon.ico等等)所有都获取完毕,区别只是头部的 GET / HTTP/1.1
会变成 GET /$(相对www.google.com的URL) HTTP/1.1
。
若是HTML引入了 www.google.com
域名以外的资源,浏览器会回到上面解析域名那一步,按照下面的步骤往下一步一步执行,请求中的 Host
头部会变成另外的域名。
HTTPD(HTTP Daemon)在服务器端处理请求/相应。最多见的 HTTPD 有 Linux 上经常使用的 Apache 和 nginx,以及 Windows 上的 IIS。
HTTPD 接收请求
服务器验证其上已经配置了 google.com 的虚拟主机
服务器验证 google.com 接受 GET 方法
服务器验证该用户可使用 GET 方法(根据 IP 地址,身份信息等)
若是服务器安装了 URL 重写模块(例如 Apache 的 mod_rewrite 和 IIS 的 URL Rewrite),服务器会尝试匹配重写规则,若是匹配上的话,服务器会按照规则重写这个请求
服务器根据请求信息获取相应的响应内容,这种状况下因为访问路径是 "/" ,会访问首页文件(你能够重写这个规则,可是这个是最经常使用的)。
服务器会使用指定的处理程序分析处理这个文件,假如 Google 使用 PHP,服务器会使用 PHP 解析 index 文件,并捕获输出,把 PHP 的输出结果返回给请求者
当服务器提供了资源以后(HTML,CSS,JS,图片等),浏览器会执行下面的操做:
浏览器的功能是从服务器上取回你想要的资源,而后展现在浏览器窗口当中。资源一般是 HTML 文件,也多是 PDF,图片,或者其余类型的内容。资源的位置经过用户提供的 URI(Uniform Resource Identifier) 来肯定。
浏览器解释和展现 HTML 文件的方法,在 HTML 和 CSS 的标准中有详细介绍。这些标准由 Web 标准组织 W3C(World Wide Web Consortium) 维护。
不一样浏览器的用户界面大都十分接近,有不少共同的 UI 元素:
浏览器高层架构
组成浏览器的组件有:
浏览器渲染引擎从网络层取得请求的文档,通常状况下文档会分红8kB大小的分块传输。
HTML 解析器的主要工做是对 HTML 文档进行解析,生成解析树。
解析树是以 DOM 元素以及属性为节点的树。DOM是文档对象模型(Document Object Model)的缩写,它是 HTML 文档的对象表示,同时也是 HTML 元素面向外部(如Javascript)的接口。树的根部是"Document"对象。整个 DOM 和 HTML 文档几乎是一对一的关系。
解析算法
HTML不能使用常见的自顶向下或自底向上方法来进行分析。主要缘由有如下几点:
因为不能使用经常使用的解析技术,浏览器创造了专门用于解析 HTML 的解析器。解析算法在 HTML5 标准规范中有详细介绍,算法主要包含了两个阶段:标记化(tokenization)和树的构建。
解析结束以后
浏览器开始加载网页的外部资源(CSS,图像,Javascript 文件等)。
此时浏览器把文档标记为“可交互的”,浏览器开始解析处于“推迟”模式的脚本,也就是那些须要在文档解析完毕以后再执行的脚本。以后文档的状态会变为“完成”,浏览器会进行“加载”事件。
注意解析 HTML 网页时永远不会出现“语法错误”,浏览器会修复全部错误,而后继续解析。
执行同步 Javascript 代码。
<style>
标签包含的内容floated
,位置有 absolutely
或 relatively
属性的时候,会有更多复杂的计算,详见http://dev.w3.org/csswg/css2/ 和 http://www.w3.org/Style/CSS/current-work渲染结束后,浏览器根据某些时间机制运行JavaScript代码(好比Google Doodle动画)或与用户交互(在搜索栏输入关键字得到搜索建议)。相似Flash和Java的插件也会运行,尽管Google主页里没有。这些脚本可 以触发网络请求,也可能改变网页的内容和布局,产生又一轮渲染与绘制。