- C++服務器開發精髓
- 張遠龍
- 3000字
- 2021-07-23 18:22:04
前言
為什么寫作本書
筆者自學生時代便開始接觸 C++,工作以后先后負責過 C++客戶端和服務端的開發工作。時至今日,C++仍然是筆者最喜歡的編程語言。在筆者看來,C++一旦學成,奇妙無窮,還可以快速學習其他編程語言和技術。
本書講解了筆者近十年來使用 C++的一些經驗和技巧,著重講解基于C++的操作系統原理和服務器開發技術,希望讀者通過學習本書,可以了解如何學習 C++,以及如何成為一名合格的C++開發者。
C/C++的當前應用領域
需要注意的是,本書不細分 C 語言與 C++的區別。在通常情況下,我們可以將 C++看作C語言的一個超集。C++雖然從功能層面來看,離C語言越來越“遠”,但從語法層面來看,其大多數語法與 C 語言基本一致。對于 C++面向對象的特性,如果仔細探究的話,我們會發現 C++類方法的具體語法還是 C 語言的過程式語法,雖然這種現狀正在不斷改變。
C語言目前主要用于操作系統類偏底層的應用開發,比如Windows、Linux這樣的大型商業操作系統,以及嵌入式操作系統、嵌入式設備。有些開源軟件也會選擇 C 語言進行開發,主要是考慮程序執行效率和生成的可執行文件的體積(C代碼生成的可執行文件體積相對較小),當然,其中不乏一些歷史技術選型的原因,比如Redis、libevent、Nginx等。
在將高級語言翻譯成機器二進制碼時,C++編譯器生成了大量的額外機器碼,而這種機器碼相對于 C 語言來說不是必需的。例如,對于一個 C++類的實例方法,編譯器在生成這個方法的機器碼時,會將函數的第1個參數設置為對象的this指針地址,以此來實現對象與函數的綁定。正因如此,許多開發者都會優化和調整編譯器生成的匯編代碼。
C++當前的常見應用領域有:①我們目前見到的各種桌面應用軟件,尤其是Windows桌面軟件,例如QQ、安全類殺毒類軟件、瀏覽器等;②一些基礎軟件和高級語言的運行時環境,例如大型數據庫軟件、Java虛擬機、C#的CLR、Python編譯器和運行時環境等;③業務型應用軟件的后臺,例如大型網絡游戲的服務端和一些企業內部的應用系統等。
C++與操作系統
雖然Java、Python等的SDK或運行時環境最終也會調用操作系統API,但其自帶的SDK 或者運行時環境都提供了常見的操作系統功能。而 C++的運行時環境一般是操作系統自身,因此C++是離操作系統更近的一種編程語言,執行效率更高。
但是,C++的整套語法不具備“功能完備性”,在大多數情況下,單純地使用其本身提供的功能無法創建出任何有意義的程序,還必須借助操作系統API來實現。例如,C++本身不直接提供網絡通信功能的 SDK,必須借助操作系統提供的套接字 API 才能實現網絡通信;而對于Java來說,JDK自帶的java.net、java.io等包則提供了完整的網絡通信功能。所以,熟悉操作系統相關原理和 API 是用好 C++的前提,這也是 C++難學、對新手不友好的主要原因之一。
不過,隨著 C++標準和版本的不斷迭代,這種現狀正在改變:在 C++標準庫中引入了越來越多的功能,避免直接調用操作系統API。
不管怎樣,應用直接使用操作系統API,程序執行效率高,控制力度大,開發能力僅僅限制于操作系統本身,這是 C++的優勢之一。比如對于Java,假設操作系統提供了某個功能,但Java虛擬機不提供該功能,則開發人員也無法使用該功能。
編程大師Charles Petzold曾說過,操作系統是一個非常復雜的系統,在API之上加一層編程語言并不能消除其復雜性,最多將復雜性隱藏起來而已,而懂得系統 API 能讓我們更快地掙脫困境。
如何看待C++11/14/17/20標準
C++既支持面向對象設計(OOP),也支持以模板語法為代表的泛型編程(GP)。從最初業界和開發者翹首以盼的C++11標準開始,歷經C++14、C++17,到今天的C++20,版本差別越來越大,原來需要使用的第三庫的功能也被陸續添加到 C++標準庫中。C++標準不斷發展,遵循C++最新標準的編譯器層出不窮,C++變化越來越大、越來越快。
對于C++11、C++14、C++17乃至C++20的學習,筆者建議以實用為主,不必太糾結新標準中的一些高級特性和復雜模板,更應該學習其中實用的語法和工具庫。
如何學好C++和后端開發
首先,我們應該打好基礎。我們要熟練使用C++,還要結合具體的操作系統學習C++,熟悉某操作系統的 API 函數,以及與系統 API 關聯的各類技術,比如各種進程與線程函數、多線程資源同步函數、文件操作函數、系統時間函數、內存分配與管理函數、網絡編程、PE或ELF文件的編譯、鏈接原理等。
如果已打好基礎,就可以找一些高質量的開源項目去實戰。最好找一些沒有復雜業務的開源項目,或者是自己熟悉其業務的開源項目(如 IM 系統)。如果不熟悉其業務,那么不但要學習其業務(軟件功能),還要學習其源碼,最終兩者難以兼顧。
因此,在學習這些項目之前,應該先確定自己的學習目的。如果學習目的是學習和借鑒這款軟件的架構設計,那么建議先進行整體把握,不要一開始就迷失在細枝末節中,這叫作“粗讀”。如果學習目的是學習開源軟件在一些細節上的處理方法,那么可以有針對性地閱讀自己感興趣的模塊,深入每一行代碼。當然,學習適合自己當前階段的項目源碼才是最好的。
學習的過程一般是接觸、熟悉、模仿、創造。不管對什么開源項目,在沒有任何思路或者解決方案時,我們都應該先接觸、熟悉、不斷模仿,做到至少心中有一套對某場景的解決方案,再來談創新、批判及改造。
筆者在學習陌生的開源項目時,喜歡先將程序用調試器正常“跑”起來;然后中斷,統計當前的線程數,通過main函數從主線程追蹤其他工作線程是如何創建的;接著分析和研究各線程的用途和線程之間的交互,這樣可以做到整體性把握;最后找感興趣的細節去學習。
總之,C++是一門講究深度的編程語言,其“深度”不體現在掌握多少C++語法,而在于是否熟悉所寫的C++代碼背后的系統原理,這是需要長期積累的,當然,一旦學成,就可以快速學習其他編程語言和框架。
本書概要
本書總計 9 章,主要基于 C++,詳細講解服務器開發中基礎且重要的技術棧,以期讀者掌握“造輪子”的方法。
第1章講解C++新標準中新增的常用語言特性和類庫。
第2章講解C++開發者應該掌握的各類開發工具和工作環境,詳細、深入地講解Linux gdb調試方面的內容。毫不夸張地說,掌握了gdb調試,就等于拿到了學習各種C++開源項目的“鑰匙”。
第 3 章詳細講解多線程的原理,涵蓋 Windows和 Linux 的各類線程同步原語,以及基于線程同步技術、生產者/消費者模型衍生的隊列系統。
第4章進行操作系統層面的網絡編程重難點解析,講解Linux上的常用網絡通信模型,通過大量詳盡的代碼實例和測試,深入淺出地探究和驗證網絡通信編程的重難點技術。
第5章講解排查和定位網絡通信問題的常用開發工具。
第6章詳細講解網絡通信協議的設計思想,并從“造輪子”的角度講解常用網絡通信協議的格式、使用方法和注意事項,講解設計網絡通信協議時需要考慮的各類問題,最后對幾種常用的通信協議逐一剖析并給出具體的實現邏輯。
第7章詳細講解如何設計一個高性能的帶網絡通信組件的服務,并結合一些經典案例進行分析,還詳細講解經典服務框架的設計思路和各個模塊的具體實現方法。
第8章以redis-server源碼為例,論證第7章講解的服務設計原理。
第9章是對第7章內容的補充,詳細講解一個服務的常用模塊設計思路。
相關資源
本書提供源碼下載、讀者交流群等服務,詳情請參見本書封底的讀者服務信息。
若想獲取關于高性能服務器開發的更多知識,可以關注筆者的兩個微信公眾號:“高性能服務器開發”和“程序員小方”。
致謝
感謝筆者的妻子承擔家務及照顧筆者的生活,讓筆者可以集中精力寫作本書。
感謝各位同事幫助筆者成長與提高。
感謝王旭東等同學為本書的校對和勘誤做出貢獻,感謝“高性能服務器開發”群內小伙伴們的支持。
感謝電子工業出版社工作嚴謹、高效的張國霞編輯,她在成書過程中對筆者的指導、協助和鞭策,是本書得以完成的重要助力。