第一個(gè)問(wèn)題:從輸入 URL 到瀏覽器接收的過(guò)程中發(fā)生了什么事情唉锌?
從觸屏到 CPU
首先是「輸入 URL」,大部分人的第一反應(yīng)會(huì)是鍵盤竿奏,不過(guò)為了與時(shí)俱進(jìn)袄简,這里將介紹觸摸屏設(shè)備的交互。
觸摸屏一種傳感器泛啸,目前大多是基于電容(Capacitive)來(lái)實(shí)現(xiàn)的绿语,以前都是直接覆蓋在顯示屏上的,不過(guò)最近出現(xiàn)了 3 種嵌入到顯示屏中的技術(shù)平痰,第一種是 iPhone 5 的 In-cell汞舱,它能減小了 0.5 毫米的厚度,第二種是三星使用的 On-cell 技術(shù)宗雇,第三種是國(guó)內(nèi)廠商喜歡用的 OGS 全貼合技術(shù)昂芜,具體細(xì)節(jié)可以閱讀這篇文章。
當(dāng)手指在這個(gè)傳感器上觸摸時(shí)赔蒲,有些電子會(huì)傳遞到手上泌神,從而導(dǎo)致該區(qū)域的電壓變化良漱,觸摸屏控制器芯片根據(jù)這個(gè)變化就能計(jì)算出所觸摸的位置,然后通過(guò)總線接口將信號(hào)傳到 CPU 的引腳上欢际。
以 Nexus 5 為例母市,它所使用的觸屏控制器是Synaptics S3350B,總線接口為I2C损趋,以下是 Synaptics 觸摸屏和處理器連接的示例:
左邊是處理器患久,右邊是觸摸屏控制器,中間的 SDA 和 SCL 連線就是 I2C 總線接口浑槽。
CPU 內(nèi)部的處理
移動(dòng)設(shè)備中的 CPU 并不是一個(gè)單獨(dú)的芯片蒋失,而是和 GPU 等芯片集成在一起,被稱為 SoC(片上系統(tǒng))桐玻。
前面提到了觸屏和 CPU 的連接篙挽,這個(gè)連接和大部分計(jì)算機(jī)內(nèi)部的連接一樣,都是通過(guò)電氣信號(hào)來(lái)進(jìn)行通信的镊靴,也就是電壓高低的變化铣卡,如下面的時(shí)序圖:
在時(shí)鐘的控制下,這些電流會(huì)經(jīng)過(guò)MOSFET晶體管偏竟,晶體管中包含 N 型半導(dǎo)體和 P 型半導(dǎo)體煮落,通過(guò)電壓就能控制線路開(kāi)閉,然后這些 MOSFET 構(gòu)成了CMOS踊谋,接著再由 CMOS 實(shí)現(xiàn)「與」「或」「非」等邏輯電路門州邢,最后由邏輯電路門上就能實(shí)現(xiàn)加法、位移等計(jì)算褪子,整體如下圖所示(來(lái)自《計(jì)算機(jī)體系結(jié)構(gòu)》):
除了計(jì)算,在 CPU 中還需要存儲(chǔ)單元來(lái)加載和存儲(chǔ)數(shù)據(jù)骗村,這個(gè)存儲(chǔ)單元一般通過(guò)觸發(fā)器(Flip-flop)來(lái)實(shí)現(xiàn)嫌褪,稱為寄存器。
以上這些概念都比較抽象胚股,推薦閱讀「How to Build an 8-Bit Computer」這篇文章笼痛,作者基于晶體管、二極管琅拌、電容等原件制作了一個(gè) 8 位的計(jì)算機(jī)缨伊,支持簡(jiǎn)單匯編指令和結(jié)果輸出,雖然現(xiàn)代 CPU 的實(shí)現(xiàn)要比這個(gè)復(fù)雜得多进宝,但基本原理還是一樣的刻坊。
另外其實(shí)我也是剛開(kāi)始學(xué)習(xí) CPU 芯片的實(shí)現(xiàn),所以就不在這誤人子弟了党晋,感興趣的讀者請(qǐng)閱讀本節(jié)后面推薦的書(shū)籍谭胚。
從 CPU 到操作系統(tǒng)內(nèi)核
前面說(shuō)到觸屏控制器將電氣信號(hào)發(fā)送到 CPU 對(duì)應(yīng)的引腳上徐块,接著就會(huì)觸發(fā) CPU 的中斷機(jī)制,以 Linux 為例灾而,每個(gè)外部設(shè)備都有一標(biāo)識(shí)符胡控,稱為中斷請(qǐng)求(IRQ)號(hào),可以通過(guò)/proc/interrupts文件來(lái)查看系統(tǒng)中所有設(shè)備的中斷請(qǐng)求號(hào)旁趟,以下是 Nexus 7 (2013) 的部分結(jié)果:
shell@flo:/ $ cat /proc/interrupts
CPU0
17:? ? ? ? ? 0? ? ? GIC? dg_timer
294:? ? 1973609? msmgpio? elan-ktf3k
314:? ? ? ? 679? msmgpio? KEY_POWER
因?yàn)?Nexus 7 使用了 ELAN 的觸屏控制器昼激,所以結(jié)果中的 elan-ktf3k 就是觸屏的中斷請(qǐng)求信息,其中 294 是中斷號(hào)锡搜,1973609 是觸發(fā)的次數(shù)(手指單擊時(shí)會(huì)產(chǎn)生兩次中斷橙困,但滑動(dòng)時(shí)會(huì)產(chǎn)生上百次中斷)。
為了簡(jiǎn)化這里不考慮優(yōu)先級(jí)問(wèn)題余爆,以 ARMv7 架構(gòu)的處理器為例纷宇,當(dāng)中斷發(fā)生時(shí),CPU 會(huì)停下當(dāng)前運(yùn)行的程序蛾方,保存當(dāng)前執(zhí)行狀態(tài)(如 PC 值)像捶,進(jìn)入 IRQ 狀態(tài)),然后跳轉(zhuǎn)到對(duì)應(yīng)的中斷處理程序執(zhí)行桩砰,這個(gè)程序一般由第三方內(nèi)核驅(qū)動(dòng)來(lái)實(shí)現(xiàn)拓春,比如前面提到的 Nexus 7 的驅(qū)動(dòng)源碼在這里touchscreen/ektf3k.c。
這個(gè)驅(qū)動(dòng)程序?qū)⒆x取 I2C 總線中傳來(lái)的位置數(shù)據(jù)亚隅,然后通過(guò)內(nèi)核的input_report_abs等方法記錄觸屏按下坐標(biāo)等信息硼莽,最后由內(nèi)核中的input 子模塊將這些信息都寫進(jìn)/dev/input/event0這個(gè)設(shè)備文件中,比如下面展示了一次觸摸事件所產(chǎn)生的信息:
130|shell@flo:/ $ getevent -lt /dev/input/event0
[? 414624.658986] EV_ABS? ? ? ABS_MT_TRACKING_ID? 0000835c
[? 414624.659017] EV_ABS? ? ? ABS_MT_TOUCH_MAJOR? 0000000b
[? 414624.659047] EV_ABS? ? ? ABS_MT_PRESSURE? ? ? 0000001d
[? 414624.659047] EV_ABS? ? ? ABS_MT_POSITION_X? ? 000003f0
[? 414624.659078] EV_ABS? ? ? ABS_MT_POSITION_Y? ? 00000588
[? 414624.659078] EV_SYN? ? ? SYN_REPORT? ? ? ? ? 00000000
[? 414624.699239] EV_ABS? ? ? ABS_MT_TRACKING_ID? ffffffff
[? 414624.699270] EV_SYN? ? ? SYN_REPORT? ? ? ? ? 00000000
從操作系統(tǒng) GUI 到瀏覽器
前面提到 Linux 內(nèi)核已經(jīng)完成了對(duì)硬件的抽象煮纵,其它程序只需要通過(guò)監(jiān)聽(tīng)/dev/input/event0文件的變化就能知道用戶進(jìn)行了哪些觸摸操作懂鸵,不過(guò)如果每個(gè)程序都這么做實(shí)在太麻煩了,所以在圖像操作系統(tǒng)中都會(huì)包含 GUI 框架來(lái)方便應(yīng)用程序開(kāi)發(fā)行疏,比如 Linux 下著名的X匆光。
但 Android 并沒(méi)有使用 X,而是自己實(shí)現(xiàn)了一套 GUI 框架酿联,其中有個(gè)EventHub的服務(wù)會(huì)通過(guò)epoll方式監(jiān)聽(tīng)/dev/input/目錄下的文件终息,然后將這些信息傳遞到 Android 的窗口管理服務(wù)(WindowManagerService)中,它會(huì)根據(jù)位置信息來(lái)查找相應(yīng)的 app贞让,然后調(diào)用其中的監(jiān)聽(tīng)函數(shù)(如 onTouch 等)周崭。
就這樣,我們解答了第一個(gè)問(wèn)題喳张,不過(guò)由于時(shí)間有限续镇,這里省略了很多細(xì)節(jié),想進(jìn)一步學(xué)習(xí)的讀者推薦閱讀以下書(shū)籍蹲姐。
擴(kuò)展學(xué)習(xí)
《計(jì)算機(jī)體系結(jié)構(gòu):量化研究方法》
《計(jì)算機(jī)組成與設(shè)計(jì):硬件/軟件接口》
《編碼》
《CPU自制入門》
《ARMv7-AR 體系結(jié)構(gòu)參考手冊(cè)》
《Linux內(nèi)核設(shè)計(jì)與實(shí)現(xiàn)》
《精通Linux設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)》
第二個(gè)問(wèn)題:瀏覽器如何向網(wǎng)卡發(fā)送數(shù)據(jù)磨取?
從瀏覽器到瀏覽器內(nèi)核
前面提到操作系統(tǒng) GUI 將輸入事件傳遞到了瀏覽器中人柿,在這過(guò)程中,瀏覽器可能會(huì)做一些預(yù)處理忙厌,比如 Chrome 會(huì)根據(jù)歷史統(tǒng)計(jì)來(lái)預(yù)估所輸入字符對(duì)應(yīng)的網(wǎng)站凫岖,比如輸入了「ba」,根據(jù)之前的歷史發(fā)現(xiàn) 90% 的概率會(huì)訪問(wèn)「www.baidu.com 」逢净,因此就會(huì)在輸入回車前就馬上開(kāi)始建立 TCP 鏈接甚至渲染了哥放,這里面還有很多其它策略,感興趣的讀者推薦閱讀High Performance Networking in Chrome爹土。
接著是輸入 URL 后的「回車」甥雕,這時(shí)瀏覽器會(huì)對(duì) URL 進(jìn)行檢查,首先判斷協(xié)議胀茵,如果是 http 就按照 Web 來(lái)處理社露,另外還會(huì)對(duì)這個(gè) URL 進(jìn)行安全檢查,然后直接調(diào)用瀏覽器內(nèi)核中的對(duì)應(yīng)方法琼娘,比如WebView中的 loadUrl 方法峭弟。
在瀏覽器內(nèi)核中會(huì)先查看緩存,然后設(shè)置 UA 等 HTTP 信息脱拼,接著調(diào)用不同平臺(tái)下網(wǎng)絡(luò)請(qǐng)求的方法瞒瘸。
需要注意瀏覽器和瀏覽器內(nèi)核是不同的概念,瀏覽器指的是 Chrome熄浓、Firefox情臭,而瀏覽器內(nèi)核則是 Blink、Gecko赌蔑,瀏覽器內(nèi)核只負(fù)責(zé)渲染俯在,GUI 及網(wǎng)絡(luò)連接等跨平臺(tái)工作則是瀏覽器實(shí)現(xiàn)的
HTTP 請(qǐng)求的發(fā)送
因?yàn)榫W(wǎng)絡(luò)的底層實(shí)現(xiàn)是和內(nèi)核相關(guān)的,所以這一部分需要針對(duì)不同平臺(tái)進(jìn)行處理娃惯,從應(yīng)用層角度看主要做兩件事情:通過(guò) DNS 查詢 IP朝巫、通過(guò) Socket 發(fā)送數(shù)據(jù),接下來(lái)就分別介紹這兩方面的內(nèi)容石景。
DNS 查詢
應(yīng)用程序可以直接調(diào)用 Libc 提供的getaddrinfo()方法來(lái)實(shí)現(xiàn) DNS 查詢。
DNS 查詢其實(shí)是基于 UDP 來(lái)實(shí)現(xiàn)的拙吉,這里我們通過(guò)一個(gè)具體例子來(lái)了解它的查找過(guò)程潮孽,以下是使用dig +trace fex.baidu.com命令得到的結(jié)果(省略了一些):
; <<>> DiG 9.8.3-P1 <<>> +trace fex.baidu.com
;; global options: +cmd
.? ? ? ? ? 11157? IN? NS? g.root-servers.net.
.? ? ? ? ? 11157? IN? NS? i.root-servers.net.
.? ? ? ? ? 11157? IN? NS? j.root-servers.net.
.? ? ? ? ? 11157? IN? NS? a.root-servers.net.
.? ? ? ? ? 11157? IN? NS? l.root-servers.net.
;; Received 228 bytes from 8.8.8.8#53(8.8.8.8) in 220 ms
com.? ? ? ? ? ? 172800? IN? NS? a.gtld-servers.net.
com.? ? ? ? ? ? 172800? IN? NS? c.gtld-servers.net.
com.? ? ? ? ? ? 172800? IN? NS? m.gtld-servers.net.
com.? ? ? ? ? ? 172800? IN? NS? h.gtld-servers.net.
com.? ? ? ? ? ? 172800? IN? NS? e.gtld-servers.net.
;; Received 503 bytes from 192.36.148.17#53(192.36.148.17) in 185 ms
baidu.com.? ? ? 172800? IN? NS? dns.baidu.com.
baidu.com.? ? ? 172800? IN? NS? ns2.baidu.com.
baidu.com.? ? ? 172800? IN? NS? ns3.baidu.com.
baidu.com.? ? ? 172800? IN? NS? ns4.baidu.com.
baidu.com.? ? ? 172800? IN? NS? ns7.baidu.com.
;; Received 201 bytes from 192.48.79.30#53(192.48.79.30) in 1237 ms
fex.baidu.com.? ? ? 7200? ? IN? CNAME? fexteam.duapp.com.
fexteam.duapp.com.? 300 IN? CNAME? duapp.n.shifen.com.
n.shifen.com.? ? ? 86400? IN? NS? ns1.n.shifen.com.
n.shifen.com.? ? ? 86400? IN? NS? ns4.n.shifen.com.
n.shifen.com.? ? ? 86400? IN? NS? ns2.n.shifen.com.
n.shifen.com.? ? ? 86400? IN? NS? ns5.n.shifen.com.
n.shifen.com.? ? ? 86400? IN? NS? ns3.n.shifen.com.
;; Received 258 bytes from 61.135.165.235#53(61.135.165.235) in 2 ms
可以看到這是一個(gè)逐步縮小范圍的查找過(guò)程,首先由本機(jī)所設(shè)置的 DNS 服務(wù)器(8.8.8.8)向 DNS 根節(jié)點(diǎn)查詢負(fù)責(zé) .com 區(qū)域的域務(wù)器筷黔,然后通過(guò)其中一個(gè)負(fù)責(zé) .com 的服務(wù)器查詢負(fù)責(zé) baidu.com 的服務(wù)器往史,最后由其中一個(gè) baidu.com 的域名服務(wù)器查詢 fex.baidu.com 域名的地址。
可能你在查詢某些域名的時(shí)會(huì)發(fā)現(xiàn)和上面不一樣佛舱,最底將看到有個(gè)奇怪的服務(wù)器搶先返回結(jié)果椎例。挨决。。
這里為了方便描述订歪,忽略了很多不同的情況脖祈,比如 127.0.0.1 其實(shí)走的是loopback,和網(wǎng)卡設(shè)備沒(méi)關(guān)系刷晋;比如 Chrome 會(huì)在瀏覽器啟動(dòng)的時(shí)預(yù)先查詢 10 個(gè)你有可能訪問(wèn)的域名盖高;還有 Hosts 文件、緩存時(shí)間 TTL(Time to live)的影響等眼虱。
通過(guò) Socket 發(fā)送數(shù)據(jù)
有了 IP 地址喻奥,就可以通過(guò) Socket API 來(lái)發(fā)送數(shù)據(jù)了,這時(shí)可以選擇 TCP 或 UDP 協(xié)議捏悬,具體使用方法這里就不介紹了撞蚕,推薦閱讀Beej’s Guide to Network Programming。
HTTP 常用的是 TCP 協(xié)議过牙,由于 TCP 協(xié)議的具體細(xì)節(jié)到處都能看到甥厦,所以本文就不介紹了,這里談一下 TCP 的 Head-of-line blocking 問(wèn)題:假設(shè)客戶端的發(fā)送了 3 個(gè) TCP 片段(segments)抒和,編號(hào)分別是 1矫渔、2、3摧莽,如果編號(hào)為 1 的包傳輸時(shí)丟了庙洼,即便編號(hào) 2 和 3 已經(jīng)到達(dá)也只能等待,因?yàn)?TCP 協(xié)議需要保證順序镊辕,這個(gè)問(wèn)題在 HTTP pipelining 下更嚴(yán)重油够,因?yàn)?HTTP pipelining 可以讓多個(gè) HTTP 請(qǐng)求通過(guò)一個(gè) TCP 發(fā)送,比如發(fā)送兩張圖片征懈,可能第二張圖片的數(shù)據(jù)已經(jīng)全收到了石咬,但還得等第一張圖片的數(shù)據(jù)傳到。
為了解決 TCP 協(xié)議的性能問(wèn)題卖哎,Chrome 團(tuán)隊(duì)去年提出了QUIC協(xié)議鬼悠,它是基于 UDP 實(shí)現(xiàn)的可靠傳輸,比起 TCP亏娜,它能減少很多來(lái)回(round trip)時(shí)間焕窝,還有前向糾錯(cuò)碼(Forward Error Correction)等功能。目前 Google Plus维贺、 Gmail它掂、Google Search、blogspot溯泣、Youtube 等幾乎大部分 Google 產(chǎn)品都在使用 QUIC虐秋,可以通過(guò)chrome://net-internals/#spdy頁(yè)面來(lái)發(fā)現(xiàn)榕茧。
雖然目前除了 Google 還沒(méi)人用 QUIC,但我覺(jué)得挺有前景的客给,因?yàn)閮?yōu)化 TCP 需要升級(jí)系統(tǒng)內(nèi)核(比如Fast Open)用押。
瀏覽器對(duì)同一個(gè)域名有連接數(shù)限制,大部分是 6起愈,我以前認(rèn)為將這個(gè)連接數(shù)改大后會(huì)提升性能只恨,但實(shí)際上并不是這樣的,Chrome 團(tuán)隊(duì)有做過(guò)實(shí)驗(yàn)抬虽,發(fā)現(xiàn)從 6 改成 10 后性能反而下降了官觅,造成這個(gè)現(xiàn)象的因素有很多,如建立連接的開(kāi)銷阐污、擁塞控制等問(wèn)題休涤,而像 SPDY、HTTP 2.0 協(xié)議盡管只使用一個(gè) TCP 連接來(lái)傳輸數(shù)據(jù)笛辟,但性能反而更好功氨,而且還能實(shí)現(xiàn)請(qǐng)求優(yōu)先級(jí)。
另外手幢,因?yàn)?HTTP 請(qǐng)求是純文本格式的捷凄,所以在 TCP 的數(shù)據(jù)段中可以直接分析 HTTP 的文本,如果發(fā)現(xiàn)围来。跺涤。。
Socket 在內(nèi)核中的實(shí)現(xiàn)
前面說(shuō)到瀏覽器的跨平臺(tái)庫(kù)通過(guò)調(diào)用 Socket API 來(lái)發(fā)送數(shù)據(jù)监透,那么 Socket API 是如何實(shí)現(xiàn)的呢桶错?
以 Linux 為例,它的實(shí)現(xiàn)在這里socket.c胀蛮,目前我還不太了解院刁,推薦讀者看看Linux kernel map,它標(biāo)注出了關(guān)鍵路徑的函數(shù)粪狼,方便學(xué)習(xí)從協(xié)議棧到網(wǎng)卡驅(qū)動(dòng)的實(shí)現(xiàn)退腥。
底層網(wǎng)絡(luò)協(xié)議的具體例子
接下來(lái)如果繼續(xù)介紹 IP 協(xié)議和 MAC 協(xié)議可能很多讀者會(huì)暈,所以本節(jié)將使用Wireshark來(lái)通過(guò)具體例子講解再榄,以下是我請(qǐng)求百度首頁(yè)時(shí)抓取到的網(wǎng)絡(luò)數(shù)據(jù):
最底下是實(shí)際的二進(jìn)制數(shù)據(jù)阅虫,中間是解析出來(lái)的各個(gè)字段值,可以看到其中最底部為 HTTP 協(xié)議(Hypertext Transfer Protocol)不跟,在 HTTP 之前有 54 字節(jié)(0x36),這就是底層網(wǎng)絡(luò)協(xié)議所帶來(lái)的開(kāi)銷米碰,我們接下來(lái)對(duì)這些協(xié)議進(jìn)行分析窝革。
在 HTTP 之上是 TCP 協(xié)議(Transmission Control Protocol)购城,它的具體內(nèi)容如下圖所示:
通過(guò)底部的二進(jìn)制數(shù)據(jù),可以看到 TCP 協(xié)議是加在 HTTP 文本前面的虐译,它有 20 個(gè)字節(jié)瘪板,其中定義了本地端口(Source port)和目標(biāo)端口(Destination port)、順序序號(hào)(Sequence Number)漆诽、窗口長(zhǎng)度等信息侮攀,以下是 TCP 協(xié)議各個(gè)部分?jǐn)?shù)據(jù)的完整介紹:
0? ? ? ? ? ? ? ? ? 1? ? ? ? ? ? ? ? ? 2? ? ? ? ? ? ? ? ? 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? Source Port? ? ? ? ? |? ? ? Destination Port? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? ? ? ? ? ? ? ? Sequence Number? ? ? ? ? ? ? ? ? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? ? ? ? ? ? Acknowledgment Number? ? ? ? ? ? ? ? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? Data |? ? ? ? ? |U|A|E|R|S|F|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
| Offset| Reserved? |R|C|O|S|Y|I|? ? ? ? ? ? Window? ? ? ? ? ? |
|? ? ? |? ? ? ? ? |G|K|L|T|N|N|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? Checksum? ? ? ? ? ? |? ? ? ? Urgent Pointer? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? ? ? ? ? ? Options? ? ? ? ? ? ? ? ? ? |? ? Padding? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|? ? ? ? ? ? ? ? ? ? ? ? ? ? data? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
具體各個(gè)字段的作用這里就不介紹了,感興趣的讀者可以閱讀RFC 793厢拭,并結(jié)合抓包分析來(lái)理解兰英。
需要注意的是,在 TCP 協(xié)議中并沒(méi)有 IP 地址信息供鸠,因?yàn)檫@是在上一層的 IP 協(xié)議中定義的畦贸,如下圖所示:
IP 協(xié)議同樣是在 TCP 前面的,它也有 20 字節(jié)楞捂,在這里指明了版本號(hào)(Version)為 4薄坏,源(Source) IP 為192.168.1.106,目標(biāo)(Destination) IP 為119.75.217.56寨闹,因此 IP 協(xié)議最重要的作用就是確定 IP 地址胶坠。
因?yàn)?IP 協(xié)議中可以查看到目標(biāo) IP 地址,所以如果發(fā)現(xiàn)某些特定的 IP 地址繁堡,某些路由器就會(huì)沈善。。帖蔓。
但是矮瘟,光靠 IP 地址是無(wú)法進(jìn)行通信的,因?yàn)?IP 地址并不和某臺(tái)設(shè)備綁定塑娇,比如你的筆記本的 IP 在家中是192.168.1.1澈侠,但到公司就變成172.22.22.22了,所以在底層通信時(shí)需要使用一個(gè)固定的地址埋酬,這就是 MAC(media access control) 地址哨啃,每個(gè)網(wǎng)卡出廠時(shí)的 MAC 地址都是固定且唯一的。
因此再往上就是 MAC 協(xié)議写妥,它有 14 字節(jié)拳球,如下所示:
當(dāng)一臺(tái)電腦加入網(wǎng)絡(luò)時(shí),需要通過(guò)ARP協(xié)議告訴其它網(wǎng)絡(luò)設(shè)備它的 IP 及對(duì)應(yīng)的 MAC 地址是什么珍特,這樣其它設(shè)備就能通過(guò) IP 地址來(lái)查找對(duì)應(yīng)的設(shè)備了祝峻。
最頂上的 Frame 是代表 Wireshark 的抓包序號(hào),并不是網(wǎng)絡(luò)協(xié)議
就這樣,我們解答了第二個(gè)問(wèn)題莱找,不過(guò)其實(shí)這里面還有很多很多細(xì)節(jié)沒(méi)介紹酬姆,建議大家通過(guò)下面的書(shū)籍進(jìn)一步學(xué)習(xí)。
擴(kuò)展學(xué)習(xí)
《計(jì)算機(jī)網(wǎng)絡(luò):自頂向下方法與Internet特色》
第三個(gè)問(wèn)題:數(shù)據(jù)如何從本機(jī)網(wǎng)卡發(fā)送到服務(wù)器奥溺?
從內(nèi)核到網(wǎng)絡(luò)適配器(Network Interface Card)
前面說(shuō)到調(diào)用 Socket API 后內(nèi)核會(huì)對(duì)數(shù)據(jù)進(jìn)行底層協(xié)議棧的封裝辞色,接下來(lái)啟動(dòng)DMA控制器,它將從內(nèi)存中讀取數(shù)據(jù)寫入網(wǎng)卡浮定。
以 Nexus 5 為例相满,它使用的是博通BCM4339芯片通信,接口采用了 SD 卡一樣的SDIO桦卒,但這個(gè)芯片的細(xì)節(jié)并沒(méi)有公開(kāi)資料立美,所以這里就不討論了。
連接 Wi-Fi 路由
Wi-Fi 網(wǎng)卡需要通過(guò) Wi-Fi 路由來(lái)與外部通信闸盔,原理是基于無(wú)線電悯辙,通過(guò)電流變化來(lái)產(chǎn)生無(wú)線電,這個(gè)過(guò)程也叫「調(diào)制」迎吵,而反過(guò)來(lái)無(wú)線電可以引起電磁場(chǎng)變化躲撰,從而產(chǎn)生電流變化,利用這個(gè)原理就能將無(wú)線電中的信息解讀出來(lái)就叫「解調(diào)」击费,其中單位時(shí)間內(nèi)變化的次數(shù)就稱為頻率拢蛋,目前在 Wi-Fi 中所采用的頻率分為 2.4 GHz 和 5 GHz 兩種。
在同一個(gè) Wi-Fi 路由下蔫巩,因?yàn)椴捎玫念l率相同谆棱,同時(shí)使用時(shí)會(huì)發(fā)生沖突,為了解決這個(gè)問(wèn)題圆仔,Wi-Fi 采用了被稱為CSMA/CA的方法垃瞧,簡(jiǎn)單來(lái)說(shuō)就是在傳輸前先確認(rèn)信道是否已被使用,沒(méi)有才發(fā)送數(shù)據(jù)坪郭。
而同樣基于無(wú)線電原理的 2G/3G/LTE 也會(huì)遇到類似的問(wèn)題个从,但它并沒(méi)有采用 Wi-Fi 那樣的獨(dú)占方案,而是通過(guò)頻分(FDMA)歪沃、時(shí)分(TDMA)和碼分(CDMA)來(lái)進(jìn)行復(fù)用嗦锐,具體細(xì)節(jié)這里就不展開(kāi)了。
以小米路由為例沪曙,它使用的芯片是BCM 4709奕污,這個(gè)芯片由 ARM Cortex-A9 處理器及流量(Flow)硬件加速組成,使用硬件芯片可以避免經(jīng)過(guò)操作系統(tǒng)中斷液走、上下文切換等操作碳默,從而提升了性能贾陷。
路由器中的操作系統(tǒng)可以基于OpenWrt或DD-WRT來(lái)開(kāi)發(fā)的,具體細(xì)節(jié)我不太了解嘱根,所以就不展開(kāi)了昵宇。
因?yàn)閮?nèi)網(wǎng)設(shè)備的 IP 都是類似192.168.1.x這樣的內(nèi)網(wǎng)地址,外網(wǎng)無(wú)法直接向這個(gè)地址發(fā)送數(shù)據(jù)儿子,所以網(wǎng)絡(luò)數(shù)據(jù)在經(jīng)過(guò)路由時(shí),路由會(huì)修改相關(guān)地址和端口砸喻,這個(gè)操作稱為NAT映射柔逼。
最后家庭路由一般會(huì)通過(guò)雙絞線連接到運(yùn)營(yíng)商網(wǎng)絡(luò)的。
運(yùn)營(yíng)商網(wǎng)絡(luò)內(nèi)的路由
數(shù)據(jù)過(guò)雙絞線發(fā)送到運(yùn)營(yíng)商網(wǎng)絡(luò)后割岛,還會(huì)經(jīng)過(guò)很多個(gè)中間路由轉(zhuǎn)發(fā)愉适,讀者可以通過(guò) traceroute 命令或者在線可視化工具來(lái)查看這些路由的 ip 和位置。
當(dāng)數(shù)據(jù)傳遞到這些路由器后癣漆,路由器會(huì)取出包中目的地址的前綴维咸,通過(guò)內(nèi)部的轉(zhuǎn)發(fā)表查找對(duì)應(yīng)的輸出鏈路,而這個(gè)轉(zhuǎn)發(fā)表是如何得到的呢惠爽?這就是路由器中最重要的選路算法了癌蓖,可選的有很多,我對(duì)這方面并不太了解婚肆,看起來(lái)維基百科上的詞條列得很全租副。
主干網(wǎng)間的傳輸
對(duì)于長(zhǎng)線的數(shù)據(jù)傳輸,通常使用光纖作為介質(zhì)较性,光纖是基于光的全反射來(lái)實(shí)現(xiàn)的用僧,使用光纖需要專門的發(fā)射器通過(guò)電致發(fā)光(比如 LED)將電信號(hào)轉(zhuǎn)成光,比起前面介紹的無(wú)線電和雙絞線赞咙,光纖信號(hào)的抗干擾性要強(qiáng)得多责循,而且能耗也小很多。
既然是基于光來(lái)傳輸數(shù)據(jù)攀操,數(shù)據(jù)傳輸速度也就取決于光的速度院仿,在真空中的光速接近于 30 萬(wàn)千米/秒,由于光纖包層(cladding)中的折射率(refractive index)為 1.52崔赌,所以實(shí)際光速是 20 萬(wàn)千米/秒左右意蛀,從首都機(jī)場(chǎng)飛往廣州白云機(jī)場(chǎng)的距離是 1967 千米,按照這個(gè)距離來(lái)算需要花費(fèi) 10 毫秒才能抵達(dá)健芭。這意味著如果你在北京县钥,服務(wù)器在廣州,等你發(fā)出數(shù)據(jù)到服務(wù)器返回?cái)?shù)據(jù)至少得等 20 毫秒慈迈,實(shí)際情況預(yù)計(jì)是 2- 3 倍若贮,因?yàn)檫@其中還有各個(gè)節(jié)點(diǎn)路由處理的耗時(shí)省有,比如我測(cè)試了一個(gè)廣州的 IP 發(fā)現(xiàn)平均延遲為 60 毫秒。
這個(gè)延遲是現(xiàn)有科技無(wú)法解決的(除非找到超過(guò)光速的方法)谴麦,只能通過(guò) CDN 來(lái)讓傳輸距離變短蠢沿,或盡量減少串行的來(lái)回請(qǐng)求(比如 TCP 建立連接所需的 3 次握手)。
IDC 內(nèi)網(wǎng)
數(shù)據(jù)通過(guò)光纖最終會(huì)來(lái)到服務(wù)器所在的 IDC 機(jī)房匾效,進(jìn)入 IDC 內(nèi)網(wǎng)舷蟀,這時(shí)可以先通過(guò)分光器將流量鏡像一份出來(lái)方便進(jìn)行安全檢查等分析,還能用來(lái)進(jìn)行面哼。野宜。。
這里的帶寬成本很高魔策,是按照峰值來(lái)結(jié)算的匈子,以每月每 Gbps(注意這里指的是 bit,而不是 Byte)為單位闯袒,北京這邊價(jià)格在十萬(wàn)人民幣以上虎敦,一般網(wǎng)站使用 1G 到 10G 不等。
接下來(lái)光纖中的數(shù)據(jù)將進(jìn)入集群(Cluster)交換機(jī)政敢,然后再轉(zhuǎn)發(fā)到機(jī)架(Rack)頂部的交換機(jī)其徙,最后通過(guò)這個(gè)交換機(jī)的端口將數(shù)據(jù)發(fā)往機(jī)架中的服務(wù)器,可以參考下圖(來(lái)自 Open Compute):
上圖左邊是正面堕仔,右邊是側(cè)面擂橘,可以看到頂部為交換機(jī)所留的位置。
以前這些交換機(jī)的內(nèi)部實(shí)現(xiàn)是封閉的摩骨,相關(guān)廠商(如思科通贞、Juniper 等)會(huì)使用特定的處理器和操作系統(tǒng),外界難以進(jìn)行靈活控制恼五,甚至有時(shí)候需要手工配置昌罩,但這幾年隨著OpenFlow技術(shù)的流行,也出現(xiàn)了開(kāi)放交換機(jī)硬件(Open Switch Hardware)灾馒,比如 Intel 的網(wǎng)絡(luò)平臺(tái)茎用,推薦感興趣的讀者建議看看它的視頻,比文字描述清晰多了睬罗。
需要注意的是轨功,一般網(wǎng)絡(luò)書(shū)中提到的交換機(jī)都只具備二層(MAC 協(xié)議)的功能,但在 IDC 中的交換器基本上都具備三層(IP 協(xié)議)的功能容达,所以不需要有專門的路由了古涧。
最后昨登,因?yàn)?CPU 處理的是電氣信號(hào)带膀,所以光纖中的光線需要先使用相關(guān)設(shè)備通過(guò)光電效應(yīng)將光信號(hào)轉(zhuǎn)成電信號(hào),然后進(jìn)入服務(wù)器網(wǎng)卡。
服務(wù)器 CPU
前面說(shuō)到數(shù)據(jù)已經(jīng)到達(dá)服務(wù)器網(wǎng)卡了芽隆,接著網(wǎng)卡會(huì)將數(shù)據(jù)拷貝到內(nèi)存中(DMA)努咐,然后通過(guò)中斷來(lái)通知 CPU显蝌,目前服務(wù)器端的 CPU 基本上都是Intel Xeon当叭,不過(guò)這幾年出現(xiàn)了一些新的架構(gòu),比如在存儲(chǔ)領(lǐng)域职祷,百度使用ARM架構(gòu)來(lái)提升存儲(chǔ)密度氏涩,因?yàn)?ARM 的功耗比 Xeon 低得多。而在高性能領(lǐng)域有梆,Google 最近在嘗試基于POWER架構(gòu)的 CPU 來(lái)開(kāi)發(fā)的服務(wù)器削葱,最新的 POWER8 處理器可以并行執(zhí)行 96 個(gè)線程,所以對(duì)高并發(fā)的應(yīng)用應(yīng)該很有幫助淳梦。
擴(kuò)展學(xué)習(xí)
第四個(gè)問(wèn)題:服務(wù)器接收到數(shù)據(jù)后會(huì)進(jìn)行哪些處理?
為了避免重復(fù)昔字,這里將不再介紹操作系統(tǒng)爆袍,而是直接進(jìn)入后端服務(wù)進(jìn)程,由于這方面有太多技術(shù)選型作郭,所以我只挑幾個(gè)常見(jiàn)的公共部分來(lái)介紹陨囊。
負(fù)載均衡
請(qǐng)求在進(jìn)入到真正的應(yīng)用服務(wù)器前,可能還會(huì)先經(jīng)過(guò)負(fù)責(zé)負(fù)載均衡的機(jī)器夹攒,它的作用是將請(qǐng)求合理地分配到多個(gè)服務(wù)器上蜘醋,同時(shí)具備具備防攻擊等功能。
負(fù)載均衡具體實(shí)現(xiàn)有很多種咏尝,有直接基于硬件的 F5压语,有操作系統(tǒng)傳輸層(TCP)上的LVS,也有在應(yīng)用層(HTTP)實(shí)現(xiàn)的反向代理(也叫七層代理)编检,接下來(lái)將介紹 LVS 及反向代理胎食。
負(fù)載均衡的策略也有很多,如果后面的多個(gè)服務(wù)器性能均衡允懂,最簡(jiǎn)單的方法就是挨個(gè)循環(huán)一遍(Round-Robin)厕怜,其它策略就不一一介紹了,可以參考 LVS 中的算法蕾总。
LVS
LVS 的作用是從對(duì)外看來(lái)只有一個(gè) IP粥航,而實(shí)際上這個(gè) IP 后面對(duì)應(yīng)是多臺(tái)機(jī)器,因此也被成為 Virtual IP生百。
前面提到的 NAT 也是一種 LVS 中的工作模式递雀,除此之外還有 DR 和 TUNNEL,具體細(xì)節(jié)這里就不展開(kāi)了置侍,它們的缺點(diǎn)是無(wú)法跨網(wǎng)段映之,所以百度自己開(kāi)發(fā)了 BVS 系統(tǒng)拦焚。
反向代理
反向代理是工作在 HTTP 上的,具體實(shí)現(xiàn)可以基于 HAProxy 或 Nginx杠输,因?yàn)榉聪虼砟芾斫?HTTP 協(xié)議赎败,所以能做非常多的事情,比如:
進(jìn)行很多統(tǒng)一處理蠢甲,比如防攻擊策略僵刮、防抓取、SSL鹦牛、gzip搞糕、自動(dòng)性能優(yōu)化等
應(yīng)用層的分流策略都能在這里做,比如對(duì) /xx 路徑的請(qǐng)求分到 a 服務(wù)器曼追,對(duì) /yy 路徑的請(qǐng)求分到 b 服務(wù)器窍仰,或者按照 cookie 進(jìn)行小流量測(cè)試等
緩存,并在后端服務(wù)掛掉的時(shí)候顯示友好的 404 頁(yè)面
監(jiān)控后端服務(wù)是否異常
??
Nginx 的代碼寫得非常優(yōu)秀礼殊,從中能學(xué)到很多驹吮,對(duì)高性能服務(wù)端開(kāi)發(fā)感興趣的讀者一定要看看。
Web Server 中的處理
請(qǐng)求經(jīng)過(guò)前面的負(fù)載均衡后晶伦,將進(jìn)入到對(duì)應(yīng)服務(wù)器上的 Web Server碟狞,比如 Apache、Tomcat婚陪、Node.JS 等族沃。
以 Apache 為例,在接收到請(qǐng)求后會(huì)交給一個(gè)獨(dú)立的進(jìn)程來(lái)處理泌参,我們可以通過(guò)編寫 Apache 擴(kuò)展來(lái)處理脆淹,但這樣開(kāi)發(fā)起來(lái)太麻煩了,所以一般會(huì)調(diào)用 PHP 等腳本語(yǔ)言來(lái)進(jìn)行處理沽一,比如在 CGI 下就是將 HTTP 中的參數(shù)放到環(huán)境變量中未辆,然后啟動(dòng) PHP 進(jìn)程來(lái)執(zhí)行,或者使用 FastCGI 來(lái)預(yù)先啟動(dòng)進(jìn)程锯玛。
(等后續(xù)有空再單獨(dú)介紹 Node.JS 中的處理)
進(jìn)入后端語(yǔ)言
前面說(shuō)到 Web Server 會(huì)調(diào)用后端語(yǔ)言進(jìn)程來(lái)處理 HTTP 請(qǐng)求(這個(gè)說(shuō)法不完全正確咐柜,有很多其它可能),那么接下來(lái)就是后端語(yǔ)言的處理了攘残,目前大部分后端語(yǔ)言都是基于虛擬機(jī)的拙友,如 PHP、Java歼郭、JavaScript遗契、Python 等,但這個(gè)領(lǐng)域的話題非常大病曾,難以講清楚牍蜂,對(duì) PHP 感興趣的讀者可以閱讀我之前寫的HHVM 介紹文章漾根,其中提到了很多虛擬機(jī)的基礎(chǔ)知識(shí)。
Web 框架(Framework)
如果你的 PHP 只是用來(lái)做簡(jiǎn)單的個(gè)人主頁(yè)「Personal Home Page」鲫竞,倒沒(méi)必要使用 Web 框架辐怕,但如果隨著代碼的增加會(huì)變得越來(lái)越難以管理,所以一般網(wǎng)站都會(huì)會(huì)基于某個(gè) Web 框架來(lái)開(kāi)發(fā)从绘,因此在后端語(yǔ)言執(zhí)行時(shí)首先進(jìn)入 Web 框架的代碼寄疏,然后由框架再去調(diào)用應(yīng)用的實(shí)現(xiàn)代碼。
可選的Web 框架非常多僵井,這里就不一一介紹了陕截。
讀取數(shù)據(jù)
這部分不展開(kāi)了,從簡(jiǎn)單的讀寫文件到數(shù)據(jù)中間層批什,這里面可選的方案實(shí)在太多农曲。
擴(kuò)展學(xué)習(xí)
《數(shù)據(jù)庫(kù)系統(tǒng)實(shí)現(xiàn)》
第五個(gè)問(wèn)題:服務(wù)器返回?cái)?shù)據(jù)后瀏覽器如何處理?
前面說(shuō)到服務(wù)端處理完請(qǐng)求后驻债,結(jié)果將通過(guò)網(wǎng)絡(luò)發(fā)回客戶端的瀏覽器朋蔫,從本節(jié)開(kāi)始將介紹瀏覽器接收到數(shù)據(jù)后的處理,值得一提的是這方面之前有一篇不錯(cuò)的文章How Browsers Work却汉,所以很多內(nèi)容我不想再重復(fù)介紹,因此將重點(diǎn)放在那篇文章所忽略的部分荷并。
從 01 到字符
HTTP 請(qǐng)求返回的 HTML 傳遞到瀏覽器后合砂,如果有 gzip 會(huì)先解壓,然后接下來(lái)最重要的問(wèn)題是要知道它的編碼是什么源织,比如同樣一個(gè)「中」字翩伪,在 UTF-8 編碼下它的內(nèi)容其實(shí)是「11100100 10111000 10101101」也就是「E4 B8 AD」,而在 GBK 下則是「11010110 11010000」谈息,也就是「D6 D0」缘屹,如何才能知道文件的編碼?可以有很多判斷方法:
用戶設(shè)置侠仇,在瀏覽器中可以指定頁(yè)面編碼
HTTP 協(xié)議中
中的 charset 屬性值
對(duì)于 JS 和 CSS
對(duì)于 iframe
如果在這些地方都沒(méi)指明轻姿,瀏覽器就很難處理,在它看來(lái)就是一堆「0」和「1」逻炊,比如「中文」互亮,它在 UTF-8 下有 6 個(gè)字節(jié),如果按照 GBK 可以當(dāng)成「涓枃」這 3 個(gè)漢字來(lái)解釋余素,瀏覽器怎么知道到底是「中文」還是「涓枃」呢豹休?
不過(guò)正常人一眼就能認(rèn)出「涓枃」是錯(cuò)的,因?yàn)檫@ 3 個(gè)字太不常見(jiàn)了桨吊,所以有人就想到通過(guò)判斷常見(jiàn)字的方法來(lái)檢測(cè)編碼威根,典型的比如 Mozilla 的UniversalCharsetDetection凤巨,不過(guò)這東東誤判率也很高,所以還是指明編碼的好洛搀。
這樣后續(xù)對(duì)文本的操作就是基于「字符」(Character)的了敢茁,一個(gè)漢字就是一個(gè)字符,不用再關(guān)心它究竟是 2 個(gè)字節(jié)還是 3 個(gè)字節(jié)姥卢。
外鏈資源的加載
(待補(bǔ)充卷要,這里有調(diào)度策略)
JavaScript 的執(zhí)行
(后續(xù)再單獨(dú)介紹,推薦大家看 R 大去年整理的這個(gè)帖子独榴,里面有非常多相關(guān)資料僧叉,另外我兩年前曾講過(guò)JavaScript 引擎中的性能優(yōu)化,雖然有些內(nèi)容不太正確了棺榔,但也可以看看)
從字符到圖片
二維渲染中最復(fù)雜的要數(shù)文字顯示了瓶堕,雖然想想似乎很簡(jiǎn)單,不就是將某個(gè)文字對(duì)應(yīng)的字形(glyph)找出來(lái)么症歇?在中文和英文中這樣做是沒(méi)問(wèn)題的郎笆,因?yàn)橐粋€(gè)字符就對(duì)應(yīng)一個(gè)字形(glyph),在字體文件中找到字形忘晤,然后畫(huà)上去就可以了宛蚓,但在阿拉伯語(yǔ)中是不行的,因?yàn)樗杏羞B體形式设塔。
(以后續(xù)再單獨(dú)介紹凄吏,這里非常復(fù)雜)
跨平臺(tái) 2D 繪制庫(kù)
在不同操作系統(tǒng)中都提供了自己的圖形繪制 API,比如 Mac OS X 下的 Quartz闰蛔,Windows 下的 GDI 以及 Linux 下的 Xlib痕钢,但它們相互不兼容,所以為了方便支持跨平臺(tái)繪圖序六,在 Chrome 中使用了Skia庫(kù)任连。
(以后再單獨(dú)介紹,Skia 內(nèi)部實(shí)現(xiàn)調(diào)用層級(jí)太多例诀,直接講代碼可能不適合初學(xué)者)
GPU 合成
(以后續(xù)再單獨(dú)介紹随抠,雖然簡(jiǎn)單來(lái)說(shuō)就是靠貼圖,但還得介紹 OpenGL 以及 GPU 芯片繁涂,內(nèi)容太長(zhǎng))
擴(kuò)展學(xué)習(xí)
這節(jié)內(nèi)容是我最熟悉暮刃,結(jié)果反而因?yàn)檫@樣才想花更多時(shí)間寫好,所以等到以后再發(fā)出來(lái)好了爆土,大家先可以先看看以下幾個(gè)站點(diǎn):
第六個(gè)問(wèn)題:瀏覽器如何將頁(yè)面展現(xiàn)出來(lái)椭懊?
前面提到瀏覽器已經(jīng)將頁(yè)面渲染成一張圖片了,接下來(lái)的問(wèn)題就是如何將這張圖片展示在屏幕上。
Framebuffer
以 Linux 為例氧猬,在應(yīng)用中控制屏幕最直接的方法是將圖像的 bitmap 寫入/dev/fb0文件中背犯,這個(gè)文件實(shí)際上一個(gè)內(nèi)存區(qū)域的映射,這段內(nèi)存區(qū)域稱為 Framebuffer盅抚。
需要注意的是在硬件加速下漠魏,如 OpenGL 是不經(jīng)過(guò) Framebuffer 的。
從內(nèi)存到 LCD
在手機(jī)的 SoC 中通常都會(huì)有一個(gè) LCD 控制器妄均,當(dāng) Framebuffer 準(zhǔn)備好后柱锹,CPU 會(huì)通過(guò)AMBA內(nèi)部總線通知 LCD 控制器,然后這個(gè)控制器讀取 Framebuffer 中的數(shù)據(jù)丰包,進(jìn)行格式轉(zhuǎn)換禁熏、伽馬校正等操作,最終通過(guò)DSI邑彪、HDMI 等接口發(fā)往 LCD 顯示器瞧毙。
以OMAP5432為例,下圖是它所支持的一種并行數(shù)據(jù)傳輸:
LCD 顯示
最后簡(jiǎn)單介紹一下 LCD 的顯示原理寄症。
首先宙彪,要想讓人眼能看見(jiàn),就必須有光線進(jìn)入有巧,要么通過(guò)反射释漆、要么有光源,比如 Kindle 所使用的 E-ink 屏幕本身是不發(fā)光的篮迎,所以必須在有光線的地方才能閱讀男图,它的優(yōu)點(diǎn)是省電,但限制太大柑潦,所以幾乎所有 LCD 都會(huì)自帶光源。
目前 LCD 中通常使用LED作為光源峻凫,LED 接上電源后渗鬼,在電壓的作用下,內(nèi)部的正負(fù)電子結(jié)合會(huì)釋放光子荧琼,從而產(chǎn)生光譬胎,這種物理現(xiàn)象叫電致發(fā)光(Electroluminescence),這在前面介紹光纖時(shí)也介紹過(guò)命锄。
以下是 iPod Touch 2 拆開(kāi)后的樣子:(來(lái)自Wikipedia):
在上圖中可以看到 6 盞 LED堰乔,這就是整個(gè)屏幕的光源,這些光源將通過(guò)反射的反射輸出到屏幕中脐恩。
有了光源還得有色彩镐侯,在 LED 中通常做法是使用彩色濾光片(Color filter)來(lái)將 LED 光源轉(zhuǎn)成不同顏色。
另外直接使用三種顏色的 LED 也是可行的驶冒,它能避免了濾光導(dǎo)致的光子浪費(fèi)苟翻,降低耗電韵卤,很適用于智能手表這樣的小屏幕,Apple 收購(gòu)的 LuxVue 公司就采用的是這種方式崇猫,感興趣的話可以去研究它的專利
LCD 屏幕上的每個(gè)物理像素點(diǎn)實(shí)際上是由紅沈条、綠、藍(lán) 3 種色彩的點(diǎn)組成诅炉,每個(gè)顏色點(diǎn)能單獨(dú)控制蜡歹,下面是用顯微鏡放大后的情況(來(lái)自Wikipedia):
從上圖可以看到每 3 種顏色的濾光片都全亮的時(shí)候就是白色,都滅就是黑色涕烧,如果你仔細(xì)看還能看到有些點(diǎn)并不是完全黑月而,這是字體上的反鋸齒效果。
通過(guò)這 3 種顏色亮度的不同組合就能產(chǎn)生出各種色彩澈魄,如果每個(gè)顏色點(diǎn)能產(chǎn)生 256 種亮度景鼠,就能生成 256 * 256 * 256 = 16777216 種色彩。
并不是所有顯示器的亮度都能達(dá)到 256痹扇,在選擇顯示器時(shí)有個(gè)參數(shù)是 8-Bit 或 6-Bit 面板铛漓,其中 8-Bit 的面板能在物理上達(dá)到 256 種亮度,而 6-Bit 的則只有 64 種鲫构,它需要靠刷新率控制(Frame rate control)技術(shù)來(lái)達(dá)到 256 的效果浓恶。
如何控制這些顏色點(diǎn)的亮度?這就要靠液晶體了结笨,液晶體的特性是當(dāng)有電流通過(guò)時(shí)會(huì)發(fā)生旋轉(zhuǎn)包晰,從而將部分光線擋住,所以只要通過(guò)電壓控制液晶體的轉(zhuǎn)動(dòng)就能控制這個(gè)顏色點(diǎn)的亮度炕吸,目前手機(jī)屏幕中通常使用 TFT 控制器來(lái)對(duì)其進(jìn)行控制伐憾,在 TFT 中最著名的要數(shù) IPS 面板。
這些過(guò)濾后的光線大部分會(huì)直接進(jìn)入眼睛赫模,有些光還會(huì)在其它表面上經(jīng)過(guò)漫(diffuse)反射或鏡面(specular)反射后再進(jìn)入眼睛树肃,加上環(huán)境光的影響,要真正算出有多少光到眼睛是一個(gè)積分問(wèn)題瀑罗,感興趣的讀者可以研究基于物理的渲染胸嘴。
當(dāng)光線進(jìn)入眼睛后,接下來(lái)就是生物學(xué)的領(lǐng)域了斩祭,所以我們到此結(jié)束劣像。
擴(kuò)展學(xué)習(xí)
《Computer Graphics, 3rd Edition : Principles and Practices》
本文所忽略的內(nèi)容
為了編寫方便,前面的介紹中將很多底層細(xì)節(jié)實(shí)現(xiàn)忽略了摧玫,比如:
內(nèi)存相關(guān)
堆耳奕,這里的分配策略有很多,比如 malloc的實(shí)現(xiàn)
棧,函數(shù)調(diào)用吮铭,已經(jīng)有很多優(yōu)秀的文章或書(shū)籍介紹了
內(nèi)存映射时迫,動(dòng)態(tài)庫(kù)加載等
隊(duì)列幾乎無(wú)處不在,但這些細(xì)節(jié)和原理沒(méi)太大關(guān)系
各種緩存
CPU 的緩存谓晌、操作系統(tǒng)的緩存掠拳、HTTP 緩存、后端緩存等等
各種監(jiān)控
很多日志會(huì)保存下來(lái)以便后續(xù)分析
FAQ
從微博反饋來(lái)看纸肉,有些問(wèn)題被經(jīng)常問(wèn)到溺欧,我就在這里統(tǒng)一回答吧,如果有其它問(wèn)題請(qǐng)?jiān)谠u(píng)論中問(wèn)柏肪。
Q:學(xué)那么多有什么用姐刁?根本用不著
A:計(jì)算機(jī)是人類最強(qiáng)大的工具,你不想了解它是如何運(yùn)作的么烦味?
Q:什么都了解一點(diǎn)聂使,還不如精通一項(xiàng)吧?
A:非常認(rèn)同谬俄,初期肯定需要先在某個(gè)領(lǐng)域精通柏靶,然后再去了解周邊領(lǐng)域的知識(shí),這樣還能讓你對(duì)之前那個(gè)領(lǐng)域有更深刻的理解溃论。
Q:曬出來(lái)培養(yǎng)一堆面霸跟自己過(guò)不去屎蜓?
A:本文其實(shí)寫得很淺,每個(gè)部分都能再深入展開(kāi)钥勋。
Q:這題要把人累死啊炬转,說(shuō)幾天都說(shuō)不完的
A:哈哈哈,大神你暴露了算灸,題目只是手段扼劈,目的是將你這樣的大牛挖掘出來(lái)。
大家的討論
非常感謝各位大牛的參與討論菲驴,這里搜集了其中的一些回答荐吵。
@WOODHEAD笨笨:請(qǐng)求被送往本地路由,接入商路由谢翎,旁路分析是否違法地址捍靠,連接被中斷沐旨,瀏覽器無(wú)辜得顯示網(wǎng)頁(yè)不存在森逮。嚴(yán)重的有人來(lái)查水表
caoz: 這不是我的面試題么! 還有一道題磁携,用戶反應(yīng)我們網(wǎng)站卡褒侧,請(qǐng)問(wèn)都有哪些可能性,以及排方法。
@caoz:寫的還是不錯(cuò)的闷供,但是還是有一些缺漏烟央,比如arp欺騙? 著名的GFW的阻斷策略歪脏,以及疑俭,一個(gè)URL可不是只有一個(gè)請(qǐng)求,多個(gè)請(qǐng)求的排隊(duì)和尋址钞艇?此外豪硅,cdn, 智能dns解析機(jī)制等。//@ZRJ-: http://t.cn/8smHpMF 從點(diǎn)擊到呈現(xiàn) — 詳解一次HTTP請(qǐng)求 我大三的時(shí)候?qū)懙钠 砚著!?啊
@唐福林:與時(shí)俱進(jìn),現(xiàn)在應(yīng)該問(wèn)從打開(kāi)app到刷新出內(nèi)容学少,整個(gè)過(guò)程中都發(fā)生了什么秧骑,如果感覺(jué)慢,怎么定位問(wèn)題乎折,怎么解決
@寒冬winter: 回復(fù)@Ivony:這題勝在區(qū)分度高绒疗,知識(shí)點(diǎn)覆蓋均勻,再不懂的人骂澄,也能答出幾句吓蘑,而高手可以根據(jù)自己擅長(zhǎng)的領(lǐng)域自由發(fā)揮,從URL規(guī)范坟冲、HTTP協(xié)議磨镶、DNS、CDN健提、到瀏覽器流式解析琳猫、CSS規(guī)則構(gòu)建、layout私痹、paint脐嫂、onload/domready统刮、JS執(zhí)行、JS API綁定??
@JS小組:[哈哈] 小編想起來(lái)了,貌似剛從業(yè)那會(huì)兒,前端界最美麗的姐@sherrie_wong 面試問(wèn)過(guò)小編這道題.然后我當(dāng)時(shí)把知道的全說(shuō)了,從瀏覽器解析,發(fā)請(qǐng)求,7層網(wǎng)絡(luò)模型實(shí)際用的模型,TCP三次握手.經(jīng)路由,交換機(jī),DNS,到服務(wù)器.在是否需要與文件系統(tǒng)還是數(shù)據(jù)庫(kù)打交道,再者分布式運(yùn)算hadoop啥的…聊了太多.
@萵怖熵崴箔:這種就是流氓問(wèn)題账千,我還想問(wèn)從你按了鍵盤到屏幕上出現(xiàn)字符侥蒙,中間都發(fā)生了什么事,提示一下:設(shè)想你是一個(gè)電子匀奏。哦鞭衩,不對(duì),電子又是什么
@寒冬winter:http://t.cn/zH20bR1 http://t.cn/zH20bR1 之前寫了開(kāi)頭兩篇娃善,后面荒廢中??
@ils傳言:不提電廠發(fā)電機(jī)轉(zhuǎn)了幾圈的也干掉醋旦!//@Philonis高:不提交換機(jī)和路由器工作原理的全干掉!//@南非蜘蛛:從7層協(xié)議的角度說(shuō)會(huì)比較全面捂人。這種問(wèn)題只有全棧工程師才能回答。
@聳肩的阿特拉斯閣下:DNS解析URL出IP/Port瑟匆,瀏覽器連接并向此地址發(fā)出GET請(qǐng)求,web服務(wù)端(nginx冕象、apache)接收到請(qǐng)求后,通過(guò)CGI等接口協(xié)議調(diào)用動(dòng)態(tài)語(yǔ)言(php等)墓律,動(dòng)態(tài)語(yǔ)言再連接數(shù)據(jù)庫(kù)查詢相應(yīng)數(shù)據(jù)并處理,然后反饋給瀏覽器齐饮,瀏覽器解析反饋?lái)?yè)面祖驱,通過(guò)html、javascript匕坯、css處理后呈現(xiàn)到屏幕??每個(gè)細(xì)節(jié)的話估計(jì)要800頁(yè)的書(shū)
@一棹凌煙:這種面試題在系統(tǒng)領(lǐng)域的招聘里其實(shí)簡(jiǎn)單好使。還有一個(gè)類似的:從在鍵盤上敲下一個(gè)字符鍵開(kāi)始术奖,到在虛擬機(jī)里的terminal里顯示出來(lái),中間的過(guò)程是什么唧龄?
@ICT_朱亞?wèn)|:記得6年前上胡偉武的芯片設(shè)計(jì)課,老胡第一節(jié)課就說(shuō)援制,上完這門課,我希望你們能搞清楚洪己,我翻了一頁(yè)P(yáng)PT,計(jì)算機(jī)內(nèi)部都做了那些流水操作拱镐,當(dāng)然啦沃琅,我是一點(diǎn)都不記得了晌柬。
@julyclyde:我們運(yùn)維一般問(wèn)一個(gè)TCP segment in a IP packet in an ethernet frame經(jīng)過(guò)一個(gè)路由器之后發(fā)生什么變化
@西西福廝:從瀏覽器說(shuō)起,操作系統(tǒng)相應(yīng)鍵盤中斷屿衅,事件隊(duì)列處理傲诵,到互聯(lián)網(wǎng)路由,到服務(wù)器網(wǎng)卡中斷栓拜,到最后輸出緩沖幕与。。诫给。細(xì)說(shuō)能說(shuō)兩小時(shí)。
@Xscape:從鍵盤中斷說(shuō)起胃榕?回車前的預(yù)解析都很靠后了..//@純白色燃燒: 從鍵盤到彈簧入萬(wàn)有引力而后直達(dá)量子力學(xué)勋又。
@Bosn:然后從硬件再到電子??量子…薛定諤之貓…平行宇宙??乃至萬(wàn)能的哲學(xué):追取!
@imPony:可深入到PN結(jié)中的電子流動(dòng)層面
@鞏小東-TX: 猜一下端铛,瀏覽器組http報(bào)文sock發(fā)出,proxy過(guò)濾换淆,收到處理頭,未過(guò)期cache返回县习,http svr處理校驗(yàn)包躁愿,轉(zhuǎn)為cgi協(xié)議給后端,后端map url逸雹,load code,與邏輯交互后生成html給svr辫樱,svr過(guò)濾cache給proxy鸡挠,proxy給瀏覽器,拉去js完成html缔逛,瀏覽器渲染褐奴。
@yuange1975:我算對(duì)整個(gè)過(guò)程比較清楚敦冬,包含服務(wù)器的處理堪遂,web服務(wù)器和瀏覽器的處理以及安全問(wèn)題溶褪,估計(jì)少有對(duì)兩者的安全都研究過(guò)的。但面試時(shí)要清晰的比較完整的把大塊流程列出來(lái)說(shuō)明白,也有難度垫言。估計(jì)也很難有機(jī)會(huì)時(shí)間去整理文章了。
@ShopEx王磊:我也問(wèn)這個(gè)問(wèn)題題好多年, 或者變通一下:從輸入U(xiǎn)RL到展現(xiàn)担忧, 都涉及到哪些緩存環(huán)節(jié), 緩存的更新機(jī)制是怎樣的
@一棹凌煙:這種面試題在系統(tǒng)領(lǐng)域的招聘里其實(shí)簡(jiǎn)單好使芝硬。還有一個(gè)類似的:從在鍵盤上敲下一個(gè)字符鍵開(kāi)始拌阴,到在虛擬機(jī)里的terminal里顯示出來(lái),中間的過(guò)程是什么?
@智慧笨蛋: 確實(shí)可以維度不同的說(shuō)摄乒,主要還是看顆粒度,光網(wǎng)絡(luò)這段從wifi 解密梨水,到NAT旦委,到局間交換摩钙,ip包在以太網(wǎng)包映射等等就可以寫一本書(shū)了
/@喬3少:放開(kāi)了說(shuō)所有互聯(lián)網(wǎng)相關(guān)的知識(shí)都能體現(xiàn)的,比如dns长踊、瀏覽器緩存,tcp連接、http響應(yīng)涨冀,web服務(wù)的工作原理鹿鳖,瀏覽器的響應(yīng)和渲染等等命满,剛剛在本子上列了下想到的安全威脅涝滴,很有意思!
最后
細(xì)心的讀者應(yīng)該會(huì)發(fā)現(xiàn)本文有隱藏內(nèi)容胶台,請(qǐng)找歼疮。。诈唬。