鏈接:https://www.zhihu.com/question/24263552/answer/27216798
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
在互聯網不太普及的時代,很多軟件公司還是會發布離線更新包,這種更新包其實就是個安裝程序,只是安裝的內容是更新的部分,沒有變化的文件直接用已經安裝的版本的。此外這些安裝程序還會修改一些系統配置以適應新版本的功能,比如注冊COM組件,修改注冊表等。
現在互聯網已經十分普及,幾乎所有軟件都采用在線升級,具體實現上,有下列幾種做法。
1. 比較簡單的,通過http協議,檢測是否有更新,就是把本地版本號發給服務器,服務器會返回一個配置文件,里面表明是否有新版本,並且帶有新版本的下載地址,更新程序按照URL下載新版本的安裝程序,然后執行這個安裝程序,用戶根據安裝程序提示進行更新。
2. 再進化一步,每次都重新安裝太麻煩,更新程序下載一個新版本的壓縮包(zip/7z),然后幫用戶解壓縮到安裝目錄。現在客戶端都追求簡單設計盡量降低和系統的耦合,基本都是復制文件就算安裝的那種綠色軟件,所以把新版本的文件一更新就能用。
3. 如果某個軟件體積已經比較大了,比如大於10MB,每次都下載一個完整的新版本的話,下載就太慢,安裝也慢。既然本地已經有個安裝版本了,每次更新其實變化的東西也不是很多,那么有個軟件就下載一個更新文件的壓縮包,然后解壓縮到安裝目錄覆蓋舊文件。
4. 有的軟件更大,更新也頻繁,每次更新的exe dll模塊大多都有更新,所以還是要下載很大的更新包,於是有人用 bsdiff算法求新版本和舊版本的二進制差異,如果新版本就是修了bug改了幾行代碼,那么bsdiff生產的補丁也就幾KB,下載的二進制補丁用bspatch來更新本地版本。bsdiff的算法庫很小,大約才30+KB很容易集成到更新程序里。
5. 有的軟件更更大,即使用bsdiff產生的補丁還是很大,有人搞出了更給力的補丁算法,Chrome的方法,http://dev.chromium.org/developers/design-documents/software-updates-courgette
從介紹看,它比bsdiff生成的補丁還要小一個數量級,這個想法相當巧妙,對於那種代碼模塊為主的程序尤其有效。很多時候我們只改了幾行代碼,但是DLL模塊卻改變了很多,主要是因為代碼優化鏈接時重排造成的,如果比較匯編代碼差異就會很小,Courgette就把DLL反編譯成匯編碼,然后和舊版本的匯編碼比較得到差異,更新的時候把舊版本也反編譯打補丁然后再編譯成DLL。這樣的話如果只改了幾行代碼,那么生成的補丁可能就幾十個字節。
比如 Chrome有如下的目錄結構
Chrome
+Application
+35.0.1916.153
+35.0.1916.114
chrome.exe
它用版本號做目錄名,每次升級的時候更新新版本,舊版本在另一個目錄運行不受影響。下次啟動的時候 Chrome.exe永遠加載最新版本的dll運行就好了。chrome.exe是個很小的程序,里面的邏輯就是檢測下版本號加載最新版本的dll,這樣簡單的程序本身幾乎不需要更新。
在需求的推動下,現代客戶端的升級程序已經相當復雜了,包括了支持灰度放量的新版本檢測,http斷點續傳下載,MD5完整性校驗,bsdiff/courgette 二進制補丁更新,雙目錄迭代升級等技術。到了移動app時代,以上這些技術都用不到了,操作系統壟斷了升級機制,只能通過操作系統檢測下載安裝更新,iOS做得相當徹底,Android還給app留了條自己下載apk安裝的路,但是二進制補丁完整性校驗等就徹底不需要app開發者自己操心了。