Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
迎來(lái)閱讀第三篇Windows 命令行系列文章。在這篇,我們開(kāi)始深入Windows 控制臺(tái)和命令行,它是什么,你可以用它可以做什么……和它不能做什么!
系列文章:
在開(kāi)始開(kāi)發(fā)Windows NT操作系統(tǒng)的那時(shí)候,大概是1989年,那時(shí)候還沒(méi)有GUI(圖形化用戶界面),也沒(méi)有桌面操作系統(tǒng),只有最原始的全屏的命令行界面,類似于MS-DOS的可視化界面越來(lái)越重要!Windows GUI 開(kāi)始開(kāi)發(fā)的時(shí)候是在開(kāi)發(fā)團(tuán)隊(duì)需要開(kāi)發(fā)一個(gè)基于控制臺(tái)的應(yīng)用的背景下誕生的!Windows 控制臺(tái)是第一個(gè)Windows NT的GUI應(yīng)用,并且可以保證兼容運(yùn)行繼續(xù)使用已有的Windows應(yīng)用。
Windows 控制臺(tái)最初的代碼到現(xiàn)在(2018年)已經(jīng)有30年的歷史……古老的東西,事實(shí)上,今天還有很多開(kāi)發(fā)者在使用它!
控制臺(tái)程序能做什么?
就像之前的文章說(shuō)的,終端的工作其實(shí)很簡(jiǎn)單:
但是,Windows 控制臺(tái)能做的事情有些不同:
深入Windows控制臺(tái)內(nèi)部
Windows控制臺(tái)是一種傳統(tǒng)的Win32可執(zhí)行文件,雖然它最初是用“C”編寫(xiě)的,但隨著團(tuán)隊(duì)現(xiàn)代化和模塊化控制臺(tái)的代碼庫(kù),大部分代碼都已正在遷移到現(xiàn)代C++了。
對(duì)于那些關(guān)心此類事物的人:許多人都在詢問(wèn)Windows是用C還是C++編寫(xiě)的。答案是 - 盡管NT是基于對(duì)象的設(shè)計(jì) - 像大多數(shù)操作系統(tǒng)一樣,Windows幾乎完全用C語(yǔ)言編寫(xiě)!為什么? C++在內(nèi)存占用和代碼執(zhí)行開(kāi)銷方面引入了開(kāi)銷。即使在今天,使用C++編寫(xiě)的代碼的其所隱藏的開(kāi)銷也會(huì)令人大吃一驚,但早在1990年代后期,此時(shí)內(nèi)存價(jià)格約為60$/MB(是的......每個(gè)MEGABYTE為60美元!)時(shí),vtable等隱藏機(jī)制的內(nèi)存開(kāi)銷非常高。此外,虛方法間接調(diào)用和對(duì)象解引用的開(kāi)銷可能導(dǎo)致當(dāng)時(shí)的C++代碼存在非常顯著的性能和規(guī)模損耗。雖然你仍然需要當(dāng)心,現(xiàn)代C++在現(xiàn)代計(jì)算機(jī)上的性能開(kāi)銷并不是一個(gè)值得關(guān)注的問(wèn)題,同時(shí)考慮到其安全性、可讀性和可維護(hù)性方面的優(yōu)勢(shì),這通常是一種可接受的折衷...這就是為什么我們將Console的代碼穩(wěn)步升級(jí)到現(xiàn)代C++這樣做的原因!
那么,Windows 控制臺(tái)內(nèi)部是什么樣?
在 Windows 7 之前,Windows 控制臺(tái)實(shí)例托管于核心的客戶-服務(wù)器運(yùn)行子系統(tǒng)(Client Server Runtime Subsystem,CSRSS)!然而,在 Windows 7 中,考慮到安全性和可靠性因素,控制臺(tái)從CSRSS 中剝離出來(lái),組件了一個(gè)包含如下二進(jìn)制文件的新家庭:
控制臺(tái)當(dāng)前的內(nèi)部結(jié)構(gòu)總體結(jié)構(gòu)圖就像這樣:
控制臺(tái)的核心組件包含如下內(nèi)容(自下而上):
Windows控制臺(tái)API
從上述的控制臺(tái)架構(gòu)圖中可以看出,與NIX終端不同的是,控制臺(tái)發(fā)送/接收API調(diào)用和/或數(shù)據(jù)序列化為IO控制(IOCTL)消息,而不是序列化后的文本! 甚至從(主要是Linux)命令行應(yīng)用程序接收的文本中所嵌入的ANSI/VT序列也被提取、解析并轉(zhuǎn)換為API調(diào)用!
這種差異揭示了*NIX和Windows之間關(guān)鍵的基本哲學(xué)差異:在*NIX中,“一切都是文件”,然而在Windows中,“一切都是對(duì)象”!
兩種方法都有利有弊,我們將概括之,但避免在這里進(jìn)行長(zhǎng)篇大論。請(qǐng)記住,哲學(xué)中的這一關(guān)鍵差異是Windows和* NIX之間諸多差異的基礎(chǔ)!
在 *NIX系統(tǒng)中,一切都是文件
在60年代末和70年代初Unix被第一次實(shí)現(xiàn)的時(shí)候,其中一個(gè)核心原則就是任何東西都可以被抽象成文件流,一個(gè)關(guān)鍵目標(biāo)是簡(jiǎn)化對(duì)設(shè)備和外設(shè)的訪問(wèn)處理:如果所有的設(shè)備都在系統(tǒng)中以文件系統(tǒng)的形式存在,那么現(xiàn)存的代碼就可以不做修改地直接訪問(wèn)這些設(shè)備。
這個(gè)原則影響深遠(yuǎn):你可以通過(guò)偽文件系統(tǒng)或虛擬文件系統(tǒng)來(lái)瀏覽和查詢大量的基于*NIX的系統(tǒng)和機(jī)器配置,它們僅僅是”表現(xiàn)得“像是“文件”或“文件夾”,實(shí)際可能是機(jī)器配置或硬件。
例如,在Linux中,你可以通過(guò)訪問(wèn) /proc/cpuinfo 虛擬文件節(jié)點(diǎn)來(lái)查看CPU的一些信息:
這個(gè)模型是如此簡(jiǎn)單和一致,但它也存在一些額外開(kāi)銷:從這些偽文件中提取或查詢特殊的文本信息并從執(zhí)行命令中返回,經(jīng)常需要一些工具的輔助,比如:sed,awk,perl,python等。這些工具經(jīng)常被用來(lái)寫(xiě)腳本和命令來(lái)解析文本內(nèi)容、查找特殊模式、區(qū)域和值。這些腳本可以變得非常復(fù)雜,難以維護(hù)和碎片化。如果文本的結(jié)構(gòu)、布局或格式發(fā)生變更,那么許多腳本也需要隨之更新。
在Windows中,任何事物都是對(duì)象
當(dāng)Windows NT被設(shè)計(jì)和構(gòu)建時(shí),“對(duì)象”被視為軟件設(shè)計(jì)的未來(lái):“面向?qū)ο蟆钡恼Z(yǔ)言比洞穴里的兔子更快出現(xiàn) - Simula和Smalltalk已經(jīng)建立起來(lái),而C ++正變得越來(lái)越流行。其他面向?qū)ο蟮恼Z(yǔ)言,如Python,Eiffel,Objective-C,ObjectPascal / Delphi,Java,C#等許多其他語(yǔ)言都在快速發(fā)展緊隨其后。
不可避免的是,它成型于面向?qū)ο蟠蠛脮r(shí)期(大約1989年)中,Windows NT的設(shè)計(jì)理念是“一切都是對(duì)象”。事實(shí)上,NT內(nèi)核最重要的部分之一是“對(duì)象管理器”!
Windows NT公開(kāi)了一組豐富的Win32 API,可以調(diào)用這些API來(lái)從操作系統(tǒng)獲取和/或操作對(duì)象。開(kāi)發(fā)人員使用Win32 API來(lái)收集和呈現(xiàn)* NIX偽文件和工具提供的類似信息,但是通過(guò)對(duì)象和結(jié)構(gòu)。并且因?yàn)榻馕銎鳎幾g器和分析器理解對(duì)象的結(jié)構(gòu),所以通常可以更早地捕獲許多編碼錯(cuò)誤,從而幫助驗(yàn)證程序員的意圖在語(yǔ)法和邏輯上是否正確。隨著時(shí)間的推移,這也可以減少系統(tǒng)破損,波動(dòng)和“攪動(dòng)”。
所以,回到我們關(guān)于Windows控制臺(tái)的中心討論:NT團(tuán)隊(duì)決定構(gòu)建一個(gè)“控制臺(tái)”,它在幾個(gè)關(guān)鍵領(lǐng)域區(qū)別于傳統(tǒng)的* NIX終端:
Windows控制臺(tái)的問(wèn)題
雖然Console的API已經(jīng)證明在Windows命令行工具和服務(wù)領(lǐng)域非常流行,但以API為中心的模型對(duì)命令行方案提出了一些挑戰(zhàn):
只有Windows實(shí)現(xiàn)了Console API
許多Windows命令行工具和應(yīng)用程序廣泛使用Console API。
問(wèn)題呢?這些API僅適用于Windows。
因此,結(jié)合其他差異化因素(例如過(guò)程生命周期差異等),Windows命令行應(yīng)用程序并不總是易于移植到* NIX,反之亦然。
因此,Windows生態(tài)系統(tǒng)開(kāi)發(fā)了自己的,通常類似但通常不同的命令行工具和應(yīng)用程序。這意味著用戶在使用Windows時(shí)必須學(xué)習(xí)一組命令行應(yīng)用程序和工具,shell,腳本語(yǔ)言等,而在使用* NIX時(shí)則需要學(xué)習(xí)另一組。
這個(gè)問(wèn)題沒(méi)有簡(jiǎn)單的快速解決方案:Windows控制臺(tái)和命令行不能簡(jiǎn)單地丟棄并被bash和iTerm2取代 - 有數(shù)以億計(jì)的應(yīng)用程序和腳本依賴于Windows控制臺(tái)和Cmd / PowerShell shells。
像Cygwin這樣的第三方工具可以很好地將許多核心GNU工具和兼容性庫(kù)移植到Windows,但是它們無(wú)法運(yùn)行未移植的,未經(jīng)修改的Linux二進(jìn)制文件。這非常重要,因?yàn)樵S多Ruby,Python,Node包和模塊依賴于或包裝Linux二進(jìn)制文件,或者依賴于* NIX運(yùn)轉(zhuǎn)狀態(tài)。
這些原因促使微軟通過(guò)在 Windows的子系統(tǒng)Linux(WSL)上本地運(yùn)行真正的,未經(jīng)修改的Linux二進(jìn)制文件和工具來(lái)擴(kuò)展Windows的兼容性。使用WSL的用戶現(xiàn)在可以在同一臺(tái)機(jī)器上并行下載和安裝一個(gè)或多個(gè)Linux發(fā)行版,并使用apt / zypper / npm / gem / etc.安裝和運(yùn)行絕大多數(shù)Linux命令行工具以及他們喜歡的Windows應(yīng)用程序和工具。
但是,還有一些控制臺(tái)提供的東西尚未被非Microsoft終端采用:具體來(lái)說(shuō),Windows控制臺(tái)提供命令歷史記錄和命令別名服務(wù),從而無(wú)需每個(gè)命令行shell(特別是)重新實(shí)現(xiàn)相同的功能。
把 Windows 命令行遠(yuǎn)程化是困難的
正如我們?cè)?Command-Line Backgrounder 一文中所討論的那樣,終端最初與它們所連接的計(jì)算機(jī)是分開(kāi)的。快進(jìn)到今天,這種設(shè)計(jì)仍然存在:大多數(shù)現(xiàn)代終端和命令行應(yīng)用程序/shell 等等是由進(jìn)程或機(jī)器邊界分隔的。
在基于 *NIX 的平臺(tái)上,終端和命令行應(yīng)用程序的分離并通過(guò)簡(jiǎn)單的字符進(jìn)行通信的概念導(dǎo)致 *NIX 命令行易于從遠(yuǎn)程計(jì)算機(jī)/設(shè)備訪問(wèn)和操作:只要終端和命令行應(yīng)用程序可以通過(guò)某種類型的有序串行通信基礎(chǔ)架構(gòu)(TTY/PTY 等)傳輸字符流,遠(yuǎn)程操作 *NIX 機(jī)器的命令行是非常簡(jiǎn)單的。
但是在 Windows 上,許多命令行應(yīng)用程序依賴于調(diào)用 Console API,并假設(shè)它們與控制臺(tái)本身在同一臺(tái)機(jī)器上運(yùn)行。這使得遠(yuǎn)程操作 Windows 命令行 shell/工具等變得很困難:在遠(yuǎn)程計(jì)算機(jī)上運(yùn)行的命令行應(yīng)用程序如何調(diào)用在用戶本地計(jì)算機(jī)的控制臺(tái)上的 API 呢?更糟糕的是,如果遠(yuǎn)程命令行應(yīng)用程序通過(guò) Mac 或 Linux 機(jī)器上的終端訪問(wèn),它如何調(diào)用 Console API 呢?!
很抱歉開(kāi)個(gè)玩笑,但我們將在以后的文章中更詳細(xì)地闡釋這個(gè)主題!
啟動(dòng)控制臺(tái)或者不!
通常,在基于 *NIX 的系統(tǒng)上,當(dāng)用戶想要啟動(dòng)一個(gè)命令行工具時(shí),他們首先會(huì)啟動(dòng)一個(gè)終端。然后終端啟動(dòng)一個(gè)默認(rèn)的 shell ,或者可以配置為啟動(dòng)一個(gè)特定的應(yīng)用程序/工具。終端和命令行應(yīng)用程序通過(guò)偽終端(PTY)交換字符流進(jìn)行通信,直到一個(gè)或兩個(gè)字符終止。
然而,在 Windows 系統(tǒng)上,事情就不一樣了:Windows 用戶永遠(yuǎn)不會(huì)啟動(dòng)控制臺(tái)(conhost.exe)——然而他們會(huì)啟動(dòng)像是 Cmd.exe,PowerShell.exe,wsl.exe 等等這樣的命令行 shell 和應(yīng)用程序。Windows 系統(tǒng)將新啟動(dòng)的應(yīng)用程序連接到當(dāng)前控制臺(tái)(如果是從命令行啟動(dòng)的話),或者連接到新創(chuàng)建的控制臺(tái)實(shí)例。
# 現(xiàn)在要說(shuō)的?
是的,在 Windows 系統(tǒng)中,用戶啟動(dòng)命令行應(yīng)用程序,而不是控制臺(tái)本身。
如果用戶從現(xiàn)有的命令行 shell 啟動(dòng)命令行應(yīng)用程序,Windows 通常會(huì)將新啟動(dòng)的 .exe(可執(zhí)行文件) 附加到當(dāng)前控制臺(tái)。否則,Windows 會(huì)將一個(gè)新的控制臺(tái)實(shí)例與新推出的應(yīng)用程序綁定在一起。
小白說(shuō):很多人說(shuō)“命令行程序在控制臺(tái)運(yùn)行”。這不是真的,而且導(dǎo)致很多關(guān)于控制臺(tái)和命令行應(yīng)用程序如何工作的困惑!命令行應(yīng)用程序和它們的控制臺(tái)都在各自獨(dú)立的 Win32 進(jìn)程中運(yùn)行。請(qǐng)通過(guò)指出“命令行工具/應(yīng)用程序連接到控制臺(tái)運(yùn)行”(或類似的)來(lái)幫助糾正這種誤解。謝謝!
聽(tīng)起來(lái)不錯(cuò),對(duì)吧?嗯…不;這里有一些問(wèn)題:
1.控制臺(tái)和命令行應(yīng)用程序通過(guò)經(jīng)由驅(qū)動(dòng)程序的 IOCTL 消息進(jìn)行通信,而不是通過(guò)文本流進(jìn)行通信
2.windows 要求 ConHost.exe 必須是連接到命令行應(yīng)用程序的控制臺(tái)程序
3.Windows 控制了控制臺(tái)和命令行應(yīng)用程序通信之間通信“管道”的創(chuàng)建
這些都是明顯的限制:如果你想為 Windows 創(chuàng)建一個(gè)替代控制臺(tái)的應(yīng)用程序,該怎么辦?你將如何發(fā)送鍵盤(pán)、鼠標(biāo)、筆等等外設(shè)的信息?如果你無(wú)法訪問(wèn)連接你新控制臺(tái)和命令行應(yīng)用程序的通信“管道”,用戶將怎么對(duì)命令行應(yīng)用程序進(jìn)行操作?
遺憾的是,這些情況并不好:有一些很棒的用于 Windows 的第三方控制臺(tái)(和服務(wù)器應(yīng)用程序)(例如 ConEmu/Cmder, Console2/ConsoleZ, Hyper, Visual Studio Code, OpenSSH 等),他們必須通過(guò)離奇的跳轉(zhuǎn)才能像正常的控制臺(tái)一樣運(yùn)行!
舉例來(lái)說(shuō),第三方控制臺(tái)必須在屏幕外啟動(dòng)一個(gè)命令行應(yīng)用程序,例如(-32000,-32000)。然后,他們必須向屏幕外控制臺(tái)發(fā)送擊鍵信息,然后收集屏幕外控制臺(tái)的文本內(nèi)容并在自己的 UI 上重新繪制它們!
我知道,這很瘋狂,對(duì)吧? !這證明了這些應(yīng)用程序創(chuàng)造者們的獨(dú)創(chuàng)性和決心,這些程序甚至還在有效的運(yùn)行!
這顯然是我們急于補(bǔ)救的一種情況。請(qǐng)繼續(xù)關(guān)注這部分內(nèi)容的更多信息——在這方面有一些好消息!
Windows 控制臺(tái) & VT
如上所述,Windows 控制臺(tái)提供了大量 API。使用控制臺(tái) API,命令行應(yīng)用程序和工具可寫(xiě)入文本,更改文本顏色,移動(dòng)光標(biāo)等。并且,由于控制臺(tái) API 的存在,Windows 控制臺(tái)幾乎不需要支持 ANSI/VT 序列,這些序列在其他平臺(tái)上提供非常類似的功能。
實(shí)際上,在 Windows 10 之前,Windows 控制臺(tái)僅實(shí)現(xiàn)了對(duì) ANSI/VT 序列的最低限度支持:
從2014年開(kāi)始,微軟組建了一個(gè)新的 Windows 控制臺(tái)團(tuán)隊(duì),使得這一切都發(fā)生了變化。控制臺(tái)團(tuán)隊(duì)的最高優(yōu)先級(jí)事項(xiàng)之一是實(shí)現(xiàn)對(duì) ANSI/VT 序列的全面支持,以便渲染在 Windows 子系統(tǒng)之Linux(WSL)和遠(yuǎn)程 *NIX 機(jī)器上運(yùn)行的 *NIX 應(yīng)用程序的輸出。您可以在本系列的上一篇文章中閱讀更多關(guān)于這個(gè)故事的內(nèi)容。
控制臺(tái)團(tuán)隊(duì)迅速為 Windows 10 的控制臺(tái)添加了對(duì) ANSI/VT 序列的全面支持,使用戶能夠使用和享用大量 Windows 和 Linux 命令行工具和應(yīng)用程序。
該團(tuán)隊(duì)繼續(xù)改進(jìn)和完善每個(gè)操作系統(tǒng)發(fā)布版本上的控制臺(tái)對(duì) VT 的支持,并對(duì)您在我們的 GitHub 問(wèn)題跟蹤器上提交的任何問(wèn)題表示感謝。
處理Unicode
一個(gè)快速的Unicode回顧:
Unicode或ISO/IEC 10646是一個(gè)國(guó)際標(biāo)準(zhǔn),定義了地球上幾乎每個(gè)書(shū)寫(xiě)系統(tǒng)中所使用的每個(gè)字符/字形,以及當(dāng)今使用的許多非腳本符號(hào)和字符大小的圖像(例如表情符號(hào))。目前(2018年7月),Unicode 11定義了137439個(gè)字符,包含146個(gè)現(xiàn)代和歷史文字系統(tǒng)!
Unicode還定義了幾種字符編碼,包括UTF-8, UTF-16, 和UTF-32:
由于UTF-8的高效的存儲(chǔ)要求以及在HTML頁(yè)面中的廣泛使用,它是目前最流行的編碼。
UTF-16/UCS-2都是常見(jiàn)的,盡管在已存儲(chǔ)文檔(例如網(wǎng)頁(yè)、代碼等)中其使用比例正在降低。UTF-32是很少使用的,因?yàn)樗男实颓掖鎯?chǔ)需要相當(dāng)大的空間。
很好,所以我們有有效并且高效的方式來(lái)表示和存儲(chǔ)Unicode字符了!
所以?
哎呀,Windows控制臺(tái)及其API是在創(chuàng)建Unicode之前創(chuàng)建的!
Windows控制臺(tái)將文本(隨后在屏幕上繪制)存儲(chǔ)為每個(gè)單元需要2個(gè)字節(jié)的UCS-2字符。
命令行應(yīng)用程序使用控制臺(tái)API將文本寫(xiě)入到控制臺(tái)中。處理文本的控制臺(tái)API有兩種形式 - 帶有A后綴處理的單字節(jié)/字符串的函數(shù),帶有W后綴處理雙字節(jié)(wchar)/字符串的函數(shù):
例如,WriteConsoleOutputCharacter()函數(shù)編譯為ASCII項(xiàng)目的WriteConsoleOutputCharacterA(),或Unicode項(xiàng)目的WriteConsoleOutputCharacterW()。如果需要指定處理方式,代碼中可以直接調(diào)用... A或...W后綴的函數(shù)。
注意:每個(gè)W API至少支持UCS-2,因?yàn)檫@是在進(jìn)行A/W拆分時(shí)就存在的事情,我們認(rèn)為這樣做會(huì)很棒。但許多W API已更新為在同一渠道上也支持UTF-16
。并非所有W API都可以支持UTF-16,但所有W API至少可以支持UCS-2。
此外,控制臺(tái)不支持一些較新的Unicode功能,包括零寬度連接符(ZWJ),該符號(hào)被用于連接阿拉伯語(yǔ)和印度語(yǔ)中的其他單獨(dú)字符,并將表情符號(hào)字符組合成一個(gè)可視字形!
那么如果你想在控制臺(tái)上輸出一個(gè)ninjacat表情符號(hào)或復(fù)雜的多字節(jié)中文/阿拉伯字符會(huì)怎樣呢? 糟糕的是,你做不到!
Console API不僅不支持長(zhǎng)度超過(guò)2字節(jié)/字形的Unicode字符(NinjaCat表情符號(hào)需要8個(gè)字節(jié)!),但Console內(nèi)部的UCS-2緩沖區(qū)不能存儲(chǔ)該數(shù)據(jù)的額外字節(jié),更糟糕的是 ,Console當(dāng)前的基于GDI的渲染器甚至無(wú)法繪制字形,即使緩沖區(qū)可以存儲(chǔ)它!
可嘆! 這就是遺留代碼的樂(lè)趣。
但是,我也會(huì)希望你們到此打住 - 我們將在本系列的新一篇文章中回到這個(gè)主題。 敬請(qǐng)關(guān)注!
再一次,親愛(ài)的讀者,如果你讀過(guò)以上的所有內(nèi)容,謝謝你,也祝賀你 —— 你現(xiàn)在比你的大多數(shù)朋友都更了解 Windows 控制臺(tái),甚至可能比你想知道的還要多!祝你幸運(yùn)!
在這篇文章中,我們涵蓋了很多內(nèi)容:
Windows控制臺(tái)的主要構(gòu)建模塊:
控制臺(tái)做什么?
控制臺(tái)與 *NIX 終端有什么不同
控制臺(tái)存在的問(wèn)題
在本系列的后續(xù)文章中,我們將深入探討控制臺(tái),并討論如何處理這些問(wèn)題……和更多其他內(nèi)容!
像往常一樣,請(qǐng)繼續(xù)關(guān)注我們。
本文由oschina作者參與翻譯,如有侵權(quán),請(qǐng)聯(lián)系刪除。
著網(wǎng)絡(luò)技術(shù)的發(fā)展,越來(lái)越多的應(yīng)用基于互聯(lián)網(wǎng)發(fā)布,再好的應(yīng)用,如果打開(kāi)速度慢,10個(gè)用戶會(huì)有9個(gè)用戶選擇離開(kāi),相關(guān)統(tǒng)計(jì)數(shù)據(jù)顯示,每增加0.1秒的加載延遲,將會(huì)導(dǎo)致客戶活躍度下降1%。在目前獲客成本較高,用戶面臨眾多可選項(xiàng)的情況下,如何提高用戶訪問(wèn)的體驗(yàn),給用戶留下良好的第一印象,提高ROI,是所有開(kāi)發(fā)互聯(lián)網(wǎng)應(yīng)用的企業(yè)都關(guān)注的核心問(wèn)題。
影響應(yīng)用資源加載的因素很多,服務(wù)器性能、網(wǎng)絡(luò)傳輸質(zhì)量、網(wǎng)站出口帶寬狀況、DNS解析時(shí)間、網(wǎng)頁(yè)內(nèi)容大小、終端用戶網(wǎng)絡(luò)質(zhì)量等,在云計(jì)算技術(shù)高度發(fā)達(dá)的今天,并非每一個(gè)環(huán)節(jié)的優(yōu)化都需要企業(yè)自己造輪子,更為便捷可行的選擇是:借助云服務(wù)商提供的相應(yīng)加速服務(wù)來(lái)優(yōu)化企業(yè)的應(yīng)用,可以實(shí)現(xiàn)更低的成本、更敏捷快速的建設(shè)、更強(qiáng)壯和高性能的服務(wù),用來(lái)取代傳統(tǒng)的用昂貴的成本購(gòu)買大量服務(wù)器、帶寬做自建的模式。
標(biāo)準(zhǔn)CDN服務(wù)所擅長(zhǎng)加速的內(nèi)容是靜態(tài)內(nèi)容,如文件、圖片、視頻等,通過(guò)CDN的緩存策略來(lái)緩存并實(shí)現(xiàn)加速。但互聯(lián)網(wǎng)上的應(yīng)用復(fù)雜,源站往往也會(huì)有很多經(jīng)常變化的內(nèi)容---動(dòng)態(tài)內(nèi)容,如用戶登錄、內(nèi)容搜索、視頻彈幕、直播評(píng)論、購(gòu)物交易、股票行情、體育實(shí)況等,很多時(shí)候這些應(yīng)用沒(méi)有做動(dòng)靜分離設(shè)計(jì)和動(dòng)靜內(nèi)容分別處理,這也造成很多應(yīng)用即使采用了標(biāo)準(zhǔn)CDN服務(wù),卻沒(méi)有達(dá)到很好的加速效果,因?yàn)閯?dòng)態(tài)部分內(nèi)容的加速性能并沒(méi)有得到很好的優(yōu)化。
對(duì)應(yīng)上敘的情況,我們推薦使用阿里云全站加速產(chǎn)品,阿里云全站加速產(chǎn)品是阿里云自主研發(fā)的融合了動(dòng)態(tài)加速技術(shù)和靜態(tài)加速技術(shù)的CDN產(chǎn)品,可以很好的解決頁(yè)面動(dòng)靜態(tài)資源混合、跨運(yùn)營(yíng)商、網(wǎng)絡(luò)不穩(wěn)定、單線源站、突發(fā)流量、網(wǎng)絡(luò)擁塞等諸多因素導(dǎo)致的響應(yīng)慢、丟包、服務(wù)不穩(wěn)定的問(wèn)題,全面提升全站性能和用戶體驗(yàn)。
阿里云全站加速產(chǎn)品可以有效提升靜態(tài)、動(dòng)態(tài)內(nèi)容的加速效果。下面的圖我們可以具體看下,使用全站加速產(chǎn)品前后的效果對(duì)比。從實(shí)際的測(cè)試結(jié)果圖中可以看到使用全站加速前,無(wú)論訪問(wèn)效率,還是節(jié)點(diǎn)加速效果,都較未使用前有了明顯的提升。
那阿里云全站加速怎么樣才能夠?qū)崿F(xiàn)以上的效果呢?主要通過(guò)以下四個(gè)方面完成:
第一、全球覆蓋的加速節(jié)點(diǎn)阿里云在全球有2800+節(jié)點(diǎn),這些節(jié)點(diǎn)涵蓋了中國(guó)國(guó)內(nèi)、歐洲、美洲、亞洲、非洲等全世界的大部分區(qū)域,同時(shí)這些節(jié)點(diǎn)都是互聯(lián)了當(dāng)?shù)刈詈诵牡倪\(yùn)營(yíng)商網(wǎng)絡(luò),阿里云全站加速可以保證全球用戶都能夠找到離他最近的、訪問(wèn)質(zhì)量最好的和用戶接入網(wǎng)絡(luò)運(yùn)營(yíng)商相對(duì)應(yīng)的加速節(jié)點(diǎn)。
第二、全球智能調(diào)度系統(tǒng)在上面我們講到了覆蓋,只有覆蓋還是不夠的,還需要把用戶調(diào)度到對(duì)應(yīng)的最合理的節(jié)點(diǎn),這個(gè)環(huán)節(jié)就非常取決于調(diào)度的IP庫(kù)的完善性和準(zhǔn)確性。阿里云全球智能調(diào)度系統(tǒng)結(jié)合阿里整體龐大的用戶基礎(chǔ)(淘寶、天貓、優(yōu)酷等),基于這些用戶基礎(chǔ)可以打造非常詳盡、精準(zhǔn)的用戶IP庫(kù),可以有效保證用戶接入匹配的高準(zhǔn)確度。
第三、智能自適應(yīng)緩存業(yè)界一般對(duì)于全站加速的場(chǎng)景,需要客戶手動(dòng)配置動(dòng)靜態(tài)內(nèi)容,來(lái)讓CDN平臺(tái)執(zhí)行動(dòng)態(tài)和靜態(tài)兩種加速模式。但是很多網(wǎng)站特別是中小客戶,動(dòng)靜態(tài)內(nèi)容區(qū)分不是很清晰,不便于做動(dòng)靜態(tài)的區(qū)分。全站加速推出的動(dòng)靜態(tài)智能自適應(yīng)功能,可以讓客戶不再需要繁瑣配置動(dòng)靜態(tài)內(nèi)容區(qū)分,全站加速會(huì)自動(dòng)的分析和識(shí)別請(qǐng)求和響應(yīng)特征,智能的對(duì)訪問(wèn)的內(nèi)容進(jìn)行動(dòng)靜態(tài)分類,讓可以緩存的靜態(tài)內(nèi)容避免了動(dòng)態(tài)化訪問(wèn)源站,從而降低了回源帶寬、回源時(shí)間而提升了性能。當(dāng)然,阿里云全站加速平臺(tái)也支持客戶通過(guò)自定義的方案,很方便的自行定義實(shí)動(dòng)靜態(tài)內(nèi)容加速規(guī)則。
此外,針對(duì)靜態(tài)內(nèi)容,阿里云全站加速還可以通過(guò)智能壓縮功,自動(dòng)對(duì)靜態(tài)文件進(jìn)行Gzip壓縮,以及通過(guò)頁(yè)面優(yōu)化,對(duì)當(dāng)前域名下所有HTML頁(yè)面中冗余的注釋和重復(fù)的空白符進(jìn)行優(yōu)化,以減小傳輸文件大小,減少流量支出和提升加速分發(fā)效率。
第四、智能路由對(duì)于無(wú)法緩存或者不允許緩存的內(nèi)容,最核心的處理邏輯是實(shí)現(xiàn)路徑加速,阿里云的路徑加速是通過(guò)智能路由來(lái)實(shí)現(xiàn)的,在廣泛覆蓋的節(jié)點(diǎn)之間,通過(guò)實(shí)時(shí)探測(cè)通信網(wǎng)絡(luò)質(zhì)量,并根據(jù)探測(cè)的質(zhì)量,進(jìn)行路徑的有效分析,同時(shí)結(jié)合阿里達(dá)摩院的最佳數(shù)據(jù)計(jì)算模型,提供一條從用戶的接入點(diǎn)到源站之間一個(gè)最優(yōu)的路徑,實(shí)現(xiàn)最好的加速效果。
阿里云全站加速產(chǎn)品除了通過(guò)以上的策略提供了優(yōu)秀的加速效果之外,還提供了下面的相關(guān)的功能模塊讓客戶的服務(wù)可以變得更靈活和更健壯,以及還提供了更廣泛和新穎的加速模式:
第一、源站策略1、智能回源策略全站加速除了提供最優(yōu)鏈路回源來(lái)保證最好的服務(wù)質(zhì)量的同時(shí),還提供了豐富的回源策略管理。很多客戶的場(chǎng)景處于安全和自身業(yè)務(wù)的需求,往往會(huì)有一些復(fù)雜的策略需要CDN來(lái)適配。目前全站加速在回源策略方面具有豐富的功能。
2、靈活回源配置和重試容災(zāi)策略阿里云全站加速提供了靈活的回源配置策略,可以根據(jù)需求配置多主源(可設(shè)置不同的回源權(quán)重)、主備源,源站可以使用IP和域名。
網(wǎng)絡(luò)情況瞬息萬(wàn)變,連接抖動(dòng)和擁堵時(shí)常發(fā)生,在長(zhǎng)鏈路傳輸時(shí),情況會(huì)更加嚴(yán)峻。通常情況下在回源階段,因?yàn)殒溌返募娱L(zhǎng),整體的網(wǎng)絡(luò)可控性降低。經(jīng)常會(huì)遇到回源節(jié)點(diǎn)的機(jī)房網(wǎng)絡(luò)有問(wèn)題,回源的某條運(yùn)營(yíng)商鏈路斷了等等相關(guān)的問(wèn)題。
結(jié)合阿里云全站加速的提供了多種回源配置以及回源重試容災(zāi)策略,可以避免單源站問(wèn)題、源站單IP問(wèn)題、源站偶發(fā)不通等問(wèn)題,給業(yè)務(wù)提供更健壯的一個(gè)支撐。
3、 WaitingRoom回源方案在回源的時(shí)候,有的時(shí)候會(huì)面臨一種場(chǎng)景,就是某次突發(fā)活動(dòng)請(qǐng)求的壓力非常大,舉個(gè)例子,比如在春運(yùn)火車票購(gòu)票的時(shí)候,請(qǐng)求的壓力可能是平時(shí)壓力的上百倍,短時(shí)間之內(nèi)沒(méi)有辦法擴(kuò)容這么大倍數(shù)能力的源站來(lái)解決請(qǐng)求問(wèn)題的(短時(shí)間內(nèi)擴(kuò)容源站上百倍的能力,會(huì)面臨到很大的成本壓力以及很長(zhǎng)的時(shí)間周期問(wèn)題)。針對(duì)上面這種場(chǎng)景,全站加速提供了WaitingRoom解決方案,可以靈活根據(jù)請(qǐng)求的URL、配置的回源比例、排隊(duì)時(shí)長(zhǎng),實(shí)現(xiàn)突發(fā)情況下有序的回源,保證源站服務(wù)穩(wěn)定性。
第二、全鏈路https加速我們知道HTTP協(xié)議以明文方式發(fā)送內(nèi)容,不提供任何方式的數(shù)據(jù)加密。HTTPS協(xié)議是以安全為目標(biāo)的HTTP通道, HTTPS提供了身份驗(yàn)證與加密通訊方法,被廣泛用于網(wǎng)上安全敏感的通訊,例如交易支付、金融應(yīng)用、API接口、政務(wù)信息等。
通過(guò)阿里云全站加速的控制臺(tái),可快速開(kāi)啟HTTPS協(xié)議,實(shí)現(xiàn)客戶端和全站加速之間請(qǐng)求的HTTPS加密,保障數(shù)據(jù)傳輸?shù)陌踩裕乐笻TTP明文傳輸中的被竊聽(tīng)、篡改、冒充和劫持風(fēng)險(xiǎn)。
目前主流瀏覽器已將HTTP協(xié)議標(biāo)識(shí)為不安全,若堅(jiān)持使用HTTP協(xié)議,除了安全會(huì)埋下隱患外,終端客戶在訪問(wèn)網(wǎng)站時(shí)出現(xiàn)的不安全標(biāo)識(shí),也將影響訪問(wèn)。
第三、WebSocket加速WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信,允許服務(wù)器主動(dòng)發(fā)送信息給客戶端。在WebSocket中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間創(chuàng)建持久性的連接,進(jìn)行雙向數(shù)據(jù)傳輸,客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單高效。
阿里云的全站加速產(chǎn)品也提供了對(duì)應(yīng)的Websocket加速模式,通過(guò)阿里云全站加速的Websocket, 可在視頻彈幕、在線教育筆記大綱等信息推送、股票、金融產(chǎn)品實(shí)時(shí)報(bào)價(jià)、體育實(shí)況更新、視頻會(huì)議和聊天、基于位置的應(yīng)用等場(chǎng)景中使用,能偶更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)高效地進(jìn)行通訊。
第四、IP應(yīng)用加速IP應(yīng)用加速旨在提供非標(biāo)準(zhǔn)HTTP協(xié)議用戶,特別是四層私有協(xié)議服務(wù)場(chǎng)景下,如金融類、游戲類、語(yǔ)音交互類等客戶提供網(wǎng)絡(luò)傳輸加速,降低服務(wù)的延遲和提升訪問(wèn)的可用性。
阿里云IP應(yīng)用加速可以提供:私有協(xié)議做傳輸控制、智能選路優(yōu)化網(wǎng)絡(luò)層、源站透?jìng)鳌I(yè)務(wù)透明轉(zhuǎn)發(fā)無(wú)任何侵入,可以通過(guò)IP應(yīng)用加速靈活的使用TCP、UDP等相關(guān)協(xié)議做業(yè)務(wù)的傳輸。
通過(guò)以上的了解,我們可以看到通過(guò)阿里云全站加速產(chǎn)品,可以有效的提升網(wǎng)站(APP)加速性能和用戶體驗(yàn)。在更多的業(yè)務(wù)搬到線上的時(shí)代,全站加速為游戲、在線教育、互聯(lián)網(wǎng)媒體、金融、商等行業(yè)中的數(shù)字化應(yīng)用提供了更優(yōu)的加速方案。如果您的業(yè)務(wù)中有全站加速的需求,可以通過(guò)阿里云官網(wǎng)、工單、服務(wù)群等方式進(jìn)行了解和反饋。
比Python,JavaScript才是更適合寫(xiě)爬蟲(chóng)的語(yǔ)言。原因有如下三個(gè)方面:
一、任務(wù):爬取用戶在Github上的repo信息
通過(guò)實(shí)例的方式學(xué)習(xí)爬蟲(chóng)是最好的方法,先定一個(gè)小目標(biāo):爬取github repo信息。入口URL如下,我們只需要一直點(diǎn)擊next按鈕就能夠遍歷到用戶的所有repo。
https://github.com/{{username}}?tab=repositories
獲取repo之后,可以做什么?
二、爬蟲(chóng)雙股劍:axios和jQuery
axios是JavaScript中很常用的異步網(wǎng)絡(luò)請(qǐng)求庫(kù),相比jQuery,它更輕量、更專業(yè)。既能夠用于瀏覽器端,也可以用于Node。它的語(yǔ)法風(fēng)格是promise形式的。在本任務(wù)中,只需要了解如下用法就足夠了:
axios.get(url).then((resp) => { 請(qǐng)求成功,處理resp.data中的html數(shù)據(jù) }).catch((err) => { 請(qǐng)求失敗,錯(cuò)誤處理 })
請(qǐng)求之后需要處理回復(fù)結(jié)果,處理回復(fù)結(jié)果的庫(kù)當(dāng)然是用jQuery。實(shí)際上,我們有更好的選擇:cheerio。
在node下,使用jQuery,需要使用jsdom庫(kù)模擬一個(gè)window對(duì)象,這種方法效率較低,四個(gè)字形容就是:笨重穩(wěn)妥。
如下代碼使用jQuery解析haha.html文件
fs = require("fs") jquery=require('jquery') jsdom=require('jsdom') //fs.readFileSync()返回結(jié)果是一個(gè)buffer,相當(dāng)于byte[] html = fs.readFileSync('haha.html').toString('utf8') dom= new jsdom.JSDOM(html) $=jquery(dom.window) console.log($('h1'))
cheerio只實(shí)現(xiàn)了jQuery中的DOM部分,相當(dāng)于jQuery的一個(gè)子集。cheerio的語(yǔ)法和jQuery完全一致,在使用cheerio時(shí),幾乎感覺(jué)不到它和jQuery的差異。在解析HTML方面,毫無(wú)疑問(wèn),cheerio是更好的選擇。如下代碼使用cheerio解析haha.html文件。
cheerio=require('cheerio') html=require('fs').readFileSync("haha.html").toString('utf8') $=cheerio.load(html) console.log($('h1'))
只需20余行,便可實(shí)現(xiàn)簡(jiǎn)單的github爬蟲(chóng),此爬蟲(chóng)只爬取了一頁(yè)repo列表。
var axios = require("axios") var cheerio = require("cheerio") axios.get("https://github.com/weiyinfu?tab=repositories").then(resp => { var $ = cheerio.load(resp.data) var lis = $("#user-repositories-list li") var repos = [] for (var i = 0; i < lis.length; i++) { var li = lis.eq(i) var repo = { repoName: li.find("h3").text().trim(), repoUrl: li.find("h3 a").attr("href").trim(), repoDesc: li.find("p").text().trim(), language: li.find("[itemprop=programmingLanguage]").text().trim(), star: li.find(".muted-link.mr-3").eq(0).text().trim(), fork: li.find(".muted-link.mr-3").eq(1).text().trim(), forkedFrom: li.find(".f6.text-gray.mb-1 a").text().trim() } repos.push(repo) } console.log(repos) })
三、更豐富的功能
爬蟲(chóng)不是目的,而是達(dá)成目的的一種手段。獲取數(shù)據(jù)也不是目的,從數(shù)據(jù)中提取統(tǒng)計(jì)信息并呈現(xiàn)給人才是最終目的。
在github爬蟲(chóng)的基礎(chǔ)上,我們可以擴(kuò)展出更加豐富的功能:使用echarts等圖表展示結(jié)果。
要想讓更多人使用此爬蟲(chóng)工具獲取自己的github統(tǒng)計(jì)信息,就需要將做成一個(gè)網(wǎng)站的形式,通過(guò)搜索頁(yè)面輸入用戶名,啟動(dòng)爬蟲(chóng)立即爬取github信息,然后使用echarts進(jìn)行統(tǒng)計(jì)展示。網(wǎng)站肯定也要用js作為后端,這樣才能和js爬蟲(chóng)無(wú)縫銜接,不然還要考慮跨語(yǔ)言調(diào)用。js后端有兩大web框架express和koa,二者API非常相似,并無(wú)優(yōu)劣之分,但express更加流行。
如上設(shè)計(jì)有一處用戶體驗(yàn)不佳的地方:當(dāng)啟動(dòng)爬蟲(chóng)爬取github信息時(shí),用戶可能需要等待好幾秒,這個(gè)過(guò)程不能讓用戶干等著。一種解決思路是:讓用戶看到爬蟲(chóng)爬取的進(jìn)度或者爬取過(guò)程。可以通過(guò)websocket向用戶推送爬取過(guò)程信息并在前端進(jìn)行展示。展示時(shí),使用類似控制臺(tái)的界面進(jìn)行展示。
如何存儲(chǔ)爬取到的數(shù)據(jù)呢?使用MongoDB或者文件都可以,最好實(shí)現(xiàn)兩種存儲(chǔ)方式,讓系統(tǒng)的存儲(chǔ)方式變得可配置。使用MongoDB時(shí),用到j(luò)s中的連接池框架generic-pool。
整個(gè)項(xiàng)目用到的庫(kù)包括:
試用地址:
https://weiyinfu.cn/githubstatistic/search.html?
案例地址:https://github.com/weiyinfu/GithubStatistic
原文鏈接:https://zhuanlan.zhihu.com/p/53763115
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。