当你浏览网页时计算机干了什么

当你浏览我的博客时计算机干了什么

技术思考, 计算机原理

在大学的时候, 我脑海里时常都蹦出对计算机的许多问号, 尤其是计算机是如何工作的, 为什么它如此强大, 越来越显著地改变了我们的生活.

随着知识的积累, OS, 进程, 线程, 计算机网络, web 开发, 一个个知识孤岛在某一天终于连接了起来, 形成了一个极为清晰的信息流.

我相信, 作为读者的你, 也会非常想弄明白其中原理, 或者已经弄明白但可能还有些一些疑问, 于是乎, 我将一个很常见的操作, 进行信息流分析, 尝试分层分析它们的每一步.

这个操作就是: 当你正在浏览我的这篇博客时, 计算机到底做了什么?

为了叙述方便, 我限定使用了 chrome 浏览器, nginx, unicorn, rails 来描述它们, 实际上, 这些组件都是可以替换的.

chrome 浏览器:

  1. 启动一个新的子进程, 渲染一个新的 tab
  2. 接收到用户输入的 URL, 发送网络请求 dns, 和后续的 http 请求, 等待 dns 与博客服务器响应, 最终获取到 html, css, javascript 网络数据.
  3. 按照 w3c 规范, 将 html 渲染成 dom 节点, 按照 css 的样式要求, 进行布局与效果显示.
  4. 执行其中的 javascript 代码, 根据情况修改对应的 dom 节点, 执行网络操作等.

由于这一层可以是浏览器, 也可能是爬虫, 还可能是其他什么东东, 所以统称为用户代理.( User Agent )

由于 W3C 规范十分繁锁, UI 渲染机制又十分复杂, JS执行引擎也十分 "高技术含量", 这导致我们国内还没有真正独立自主的浏览器, 全是用 ie 或者 chrome 的 "核", 自己套个壳.

浏览器的开发复杂度, 堪比编写一个完整的操作系统.

关键字 : 用户代理, w3c, HTML5, Javascript, CSS.

操作系统上层:

操作系统目前最常见的即我们平时使用的 OSX 或者 windows 8, 以及经常作为服务器的 Linux.

这一层, 它为进程提供一个容身之地: 一块内存, 一些受限的资源操作, 如读磁盘, 发网络数据, 与其他进程交互.

  1. 收到 chrome 父进程的请求, 创建一个子进程:

    • 开辟一段内存存储新进程的pid及它的环境变量, 叫做 进程描述符.
    • 收到 exec() 系列的系统调用, 准备一块内存, 加载子进程的代码, 继承父进程的运行数据.
    • 收到渲染 UI 请求, 指挥显示器显示指定的内存位置上的颜色, 这件事太麻烦了, 以后交给它的小弟 DMA 自动处理.
  2. 接收到 socket() 系列的系统调用, 指挥网卡发送指定的报文:
    • DNS 请求:

      0) 查找本机 hosts 映射文件( 例如 OSX 10.10 在 /etc/hosts ) , 如果找到就直接返回 IP 地址, 否则继续以下步骤.

      1) 在 UDP 报文中填入内容: 请求 yafeilee.me 的 IP 地址.

      2) 在 IP 报文中组装 IP: 8.8.8.8, PORT 53, 类型: DNS, 内容: 上面的 UDP 报文

      3) 在 链路层上组装 SMAC: xx:xx:xx:xx:xx:xx, DMAC: 路由器MAC. ( 如果没记录下路由MAC, 发 ARP 找)

      4) 交付给网卡, 网卡开始发送.

      5) 操作系统开始干别的事情, 等待对方响应

      6) 网卡接收到对方响应的数据, 告诉操作系统, 已经收到.

      7) 操作系统通知 chrome 进程, IP 地址已经找到, 给你.

      8) chrome 进程开始准备 HTTP 请求.

    • 组装来自上层的 HTTP 请求数据.

      1) 从 1024 - 65535 中找到一个空闲的 IO 端口, 绑定, 避免其他进程占用.

      2) 与对方(刚才找到的 IP 地址)进行三次握手, 确认对方是在线的.

      3) 按照上面的 DNS 报请求的方式, 组装好 HTTP 数据, 将数据交付网卡发送.

      4) 接收到数据后, 通知 chrome 数据已经到达. chrome 子进程可能继续请求一些数据( 例如加载图片, 其他资源等 )

操作系统是如何做到进程抽象的呢?

不难. 做到以下几点:

  1. 实现虚拟内存映射, 术语为 MMU, 通过缺页中断调用, 每一个进程可以模拟出 4G (32位总线位数下) 的独立内存, 互不干扰.
  2. 由 CPU 硬件支持 RING0 与 RING3 的至少两级切换, 使得 RING3 禁止某些指令, 例如切换 RING 和访问网卡等, 操作系统配置此特性, 并使得进程运行在 RING3 下面. 但需要访问硬件怎么办?
  3. 利用软中断提供 API 给进程调用.

至此, 在操作系统级别之上, 进程之间就互相独立了, 可以互不干扰, 也无权干扰其他进程.

关键字 : OS, 进程, 线程, 用户态, MMU, socket编程.

操作系统底层

在底层, 操作系统负责 "理解" 并执行对应的指令, 例如:

如何将数据交付给网卡, 如何获得网卡新的数据, 如何存储一个数据.

也即负责解决一个极为神奇的问题: 如何将各种指令转换成 0 与 1, 并运算结果.

  1. 一切皆可计算

    想像一下, 一段声音, 可以将它的频率数字化为 0 与 1, 存储起来, 播放的时候, 由 CPU 按照时序一点点计算出来, 并驱动音响播放声音.( 电信号要经过 CPU, 总线, 音频输出, 音响 )

    一张图像, 可以将它的每个像素都用 RGB 存储下来, 写为 0 与 1, 交给显示器显示( 显示器是专门将 RGB 数据显示为图像的设备 )

    目前, 几乎所有东西都可以数字化了.

  2. 指令运算

    首先, 布尔代数的理论的指导可以让机器用电路进行二进制运算. 布尔代数与继电器(现在是晶体管, 大规模集成电路 )可以推论造出存储器, 触发器( 时钟 ), 运算器( 计算加法 ), 控制器( 控制指令处理, 常见指令存储, 加载, 跳转, 加法 )

    有了以上的工具, CPU 就诞生了.

    所有的程序都会被编译器处理为二进制代码存储起来, 最后由 CPU 依次取出指令并处理.

  3. 操作抽象

    对于 CPU 而言, 它的针脚就是输入与输出, 网卡通过总线与 CPU 连接起来, 操作系统会设定一些参数告诉 CPU 一旦有硬件中断, 就处理预置的指令. 这种方式叫硬中断.( 可以想像, 硬中断有好多种, 硬盘, 打印机, 网卡, 鼠标, 键盘, 所以也会排个序号, 叫中断号. )

    对于应用程序, 为了系统安全, 操作系统利用 CPU 的 RING3 和 MMU 为它们抽象了进程描述符, 进程空间( 32 位默认为 4G ), 为它们提供了一套 API, 例如, 启动子进程, 与其他进程通信, 监听网络消息, 等等( 标准的 Unix 的操作系统 API 有 1000 多个), 这套 API 的调用方式也利用了 CPU 的中断处理( 默认中断号 0x80 ), 这种方式叫做软中断.

通过以上的抽象处理, 在计算机 "只懂得加法运算" 的情况下, 理解了指令 获取到网络数据, 最终驱动显示器( 如果图像运算量太大, 则可能交给显卡计算 ) 渲染出了博客内容.

关键字 : CPU原理, 图灵机, 数字化, 继电器.

网络邮递

网卡收到发送指令后, 将数据按照 0, 1 编码成高低电平组成的电气信号, 发送到网线中, 先等到网线上没有正在传送的数据, 之后便开始发送数据.

家庭路由器接受到网卡数据后, 将 MAC 与 IP 从数据报文中替换为自身的, 转发给下一级路由器.

如果用的拨号上网, 这些报文会由猫首先由数字信号转化为模拟信号, 传递至电话网的另一端: 服务提供商( ISP ), 例如电信. 他们将信号再由猫解回数字信号. 我们叫这种方式为 PPPOE 上网.

如果用的光纤, 可将数字信号直达服务商.

服务商的下一级路由器就像邮递员一样, 将邮件( 数据报文 )的邮戳与回信做一些调整, 继续发送给下一级路由器, 依次下去, 最终交付给我博客所在的 IP 地址的计算机.

每台路由器都可以理解成一个计算机.

这种方案, 被称为路由与交换技术.

关键字 : 路由, 交换, 计算机网络, 以太网.

博客服务器的回应

博客服务器运行在 VPS 上, 一个 VPS 看上去就是一个真实的电脑, 但事实上, 它是运行在一个真实的电脑上的一个虚拟电脑, 这种技术叫做虚拟化技术. 各种最近很热门的云服务商均是利用这种技术实现的.

博客服务器上也同时跑了一个操作系统, 其名为 Linux, 但没有图形界面. 其工作原理与上面的操作系统大同小异.

直接跳过操作系统的处理( 上面已经讲述了 ), 直接从博客服务器监听的进程说起, 这个进程名为 nginx master, 监听 80 端口( WEB 程序默认的端口 ), 一旦接收到一个新的请求, nginx master 判断来源, 根据配置将连接转移给它的合适的子进程 nginx worker, 自己继续监听新的请求.

worker 接收到连接请求后, 回复对端连接已就绪, 对方就 balabla... 发送请求数据过来了.

worker 将请求弄清楚, 发现这个请求是要 Ruby on Rails 的服务进程 unicorn 处理的, 将请求添加一些额外字段, 例如 X-Forwarded-For, HOST 等, 转发给 unicorn.

为什么需要这两步 "多余" 的部分呢?

  1. 一个服务器可能提供多个网站服务, 它们都必须使用 80 端口, 需要有一个分发器: nginx/apache.
  2. 为了更快的交付数据, 某些静态数据不会变, 数据会被压缩, 这些分发器处理这些内容时非常专业.

关键字 : nginx, unicorn

Ruby on Rails 进程

Ruby on Rails 只是千百 Web 开发领域中的一种, 同类的如 php, j2ee, asp.net. 本质上它们都是负责一件事:

如何让 Web 应用更高效的被开发出来, 并更快的交付给用户, 并在未来也更好维护.

unicorn 是 Rails 应用的一个生产容器, 非常的高效与易于使用.

unicorn 接收到 nginx 发过来的请求后, 将请求的 URL 与参数进行一层层分析( rack ), 由路由表查明, 发现这是交给控制器 posts_controller 的 index 方法的.

于是调用 posts#index 的方法.

posts#index 将 postgres 数据库里最新一篇的博客取出. 并把 app/views/index.html.slim 数据渲染成 html, 交付给上一层.

nginx 将数据转交给用户.

其间, 浏览器与 nginx 经过多次的交互, 最终, 图片, JS, HTML, CSS 都基本到位后, 浏览器开始渲染出最终的结果.

关键字 : web 开发, Ruby on Rails, session, cookie, 缓存.

总结一下

我尝试将所有流程都串到一起了, 这样的意义何在? 我用下面的比方来说:

假如你现在是一个酒店大厨, 你只管把原材料加上配料做成美味的饭菜即可. 你是无须知道原材料是从哪里运来的.

但只有你对原材料十分了解, 你才可能找到世界上最好的原材料, 才可能成为世界顶极的大厨.

我想, 只有好奇心能驱动我们走的更远.

至此, 对于宏观世界而言, 世界仅仅为你耗费了零点几度的电, 增加了一点熵.

附, 主要参考书目:

  1. 现代操作系统
  2. 计算机网络
  3. 深入理解计算机系统
  4. 编码的奥秘
  5. Ruby on Rails 敏捷开发

更多书目可到我的豆瓣读书列表查阅: http://www.douban.com/people/41759170/

深入补充阅读文章: https://github.com/skyline75489/what-happens-when-zh_CN

ps: 这篇文章信息量巨大, 我理解有限, 如果你发现任何错误或问题, 欢迎在下面留言给我.

时间: 2024-08-29 14:43:43

当你浏览网页时计算机干了什么的相关文章

iis浏览网页时提示无法显示 XML 页

无法显示 XML 页.         使用 样式表无法查看 XML 输入.请更正错误然后单击 刷新按钮,或以后重试.          处理资源 'http://localhost/ 时出错.第 1 行,位置: 2           <%@ Page Language="C#"    CodeFile="Main.aspx.cs" Inherits="_Default" %>          -^ 将xml转换成html需要的是

Win2003打开网页时总是提示添加网址到信任站点的设置方法

在WIN2003系统中,我们打开网页,或打开网站,或浏览网页时,老是跳出一个窗口提示"添加网址到信任站点","网页老是提示添加信任"或"2003每打开一次网页都要加入受信任站点"或"win2003提示信任站点"或"打开网页提示把此网页加入可信站点怎么处理"或"win2003打开网页提示"等等描述都是对这个问题的反应. Win2003的操作系统,的确比其它操作系统在安全上增加了不少,这是为

浏览网页错误类型大全

浏览网页错误类型大全 400 无法解析此请求. 401.1 未经授权:访问由于凭据无效被拒绝. 401.2 未经授权: 访问由于服务器配置倾向使用替代身份验证方法而被拒绝. 401.3 未经授权:访问由于 ACL 对所请求资源的设置被拒绝. 401.4 未经授权:Web 服务器上安装的筛选器授权失败. 401.5 未经授权:ISAPI/CGI 应用程序授权失败. 401.7 未经授权:由于 Web 服务器上的 URL 授权策略而拒绝访问. 403 禁止访问:访问被拒绝. 403.1 禁止访问:执

进入NGINX的世界:从只会浏览网页,迈向会搭建网站

Hello 大家好哦 先简单介绍一下我自己吧 , 大米是来自北京的运维架构师一名, 从2004年参加工作至今已经第14年了 岁数确实很大啦 但是 咱们当运维的人永远都保持着年轻的心是最重要的了 有的朋友可能要问大米了, 做运维可以干上这么多个年头吗 , 前景如何啊 待遇怎么样? [大米心中偷着乐] 这还用问吗?如果前途和待遇不行话 怎么可能一直做这么多年呢 ^_^? 接下来 又有人给大米提出问题了, 请问 运维这一行当 和 开发比起来如何呢? [闭上眼回顾一下] 其实这个问题仁者见仁智者见智 ,

制作网页时Div与Table的区别

1.制作效率 我想没人反对表格的制作效率要高于Div的效率.很明显Div布局代码全部都要手写.即使你在熟悉代码,也没有 Dreamweaver生成来的快吧!所以Table可以很容易建立起结构化的界面,通过table自身的参数定义,我们能把页面布局很快定义成我们所需要的效果. 2.浏览器的兼容问题 table和div在兼容问题中,table更具有优势. 我们常用的IE6.0,IE7.0火狐Firefox浏览器对div css设置上非常挑剔,往往同一个css在2种浏览器上会有不同的结果,对设计制作人

Android在程序中浏览网页

本文是自己学习所做笔记,欢迎转载.但请注明出处:http://blog.csdn.net/jesson20121020 有时须要在程序中浏览一些网页.当然了能够通过调用系统的浏览器来打开浏览.可是大多数情况下,这样的方式并不适用.   以下给出怎样在程序中浏览网页.先看效果图: 事实上,这里主要是利用了WebView控件及它的一些方法.   通过WebView的loadUrl(String url)能够装载指定的地址的网页内容,并显示在控件中,上一页和下一页的功能分别相应于WebView的goB

浅谈WebView在新窗口浏览网页(setSupportMultipleWindows()与onCreateWindow()关系)

一,写在前面 我们平常使用电脑浏览器浏览网页可能会有三种方式: 1.新窗口 2.当前窗口种的新选项卡 3.当前选项卡或者窗口 我们知道在电脑系统中同一时间可以开启多个相同的进程,就像你可以同时登陆2个qq一样,而在手机中,同一进程只能有一个在运行. 对比智能手机的浏览器如:QQ浏览器,百度浏览器,电脑浏览器中的新窗口相当于重新开启了一个浏览器,而在手机中,我们是使用WebView加载网页,虽然浏览器其应用进程只有一个, 但是内存中WebView对象可以有多个.在手机上的新窗口就是另外创建一个We

解决Ubuntu 14.04 LTS 浏览网页速度慢的问题

Ubuntu 14.04 (其他版本可能适用)浏览网页慢的一个重要原因是DNS默认为:172.0.0.1  查看/etc/resolv.conf 会看到他使用的dns是 nameserver 127.0.1.1 操作过程: 修改/etc/resolv.conf, 将nameserver 改为你你想用的dns server ,格式为:    nameserver xxx.xxx.xxx.xxx 系统装有NetworkManager的话, 这样的修改只是临时的, 如重启计算机, 或者插拔网线/etc

Linux中7个用来浏览网页和下载文件的命令

上一篇文章中,我们提到了rTorrent.wget.cURL.w3m.Elinks等几个有用的工具,很多人回信说还有其它几个类似的工具也值得讨论,所以就有了这篇文章.如果错过了第一部分的讨论,可以通过下面的链接来回顾. 5 个基于Linux命令行的文件下载和网站浏览工具 这篇文章介绍了Linux下用于浏览网页和下载文件的其它几个命令行工具. 1. links Links是用C语言写的一个开源web浏览器,支持包括Linux.Windows.OS X和OS/2在内的所有主流平台.它提供了基于文本和