當前位置:
首頁 > 知識 > Python 高手之路:從零開始打造一個Web伺服器

Python 高手之路:從零開始打造一個Web伺服器

文 | Ruslan Spivak譯 | EarlGrey

推薦 | 編程派公眾號(ID:codingpy)

有一天,一位女士散步時經過一個工地,看見有三個工人在幹活。她問第一個人,「你在做什麼?」第一個人有點不高興,吼道「難道你看不出來我在砌磚嗎?」女士對這個答案並不滿意,接著問第二個人他在做什麼。第二個人回答道,「我正在建造一堵磚牆。」然後,他轉向第一個人,說道:「嘿,你砌的磚已經超過牆高了。你得把最後一塊磚拿下來。」女士對這個答案還是不滿意,她接著問第三個人他在做什麼。第三個人抬頭看著天空,對她說:「我在建造這個世界上有史以來最大的教堂」。就在他望著天空出神的時候,另外兩個人已經開始爭吵多出的那塊磚。他慢慢轉向前兩個人,說道:「兄弟們,別管那塊磚了。這是一堵內牆,之後還會被刷上石灰的,沒人會注意到這塊磚。接著砌下層吧。」

這個故事的寓意在於,當你掌握了整個系統的設計,明白不同的組件是以何種方式組合在一起的(磚塊,牆,教堂)時候,你就能夠更快地發現並解決問題(多出的磚塊)。

但是,這個故事與從頭開發一個網路伺服器有什麼關係呢?

在我看來,要成為一名更優秀的程序員,你必須更好地理解自己日常使用的軟體系統,而這就包括了編程語言、編譯器、解釋器、資料庫與操作系統、網路伺服器和網路開發框架。而要想更好、更深刻地理解這些系統,你必須從頭重新開發這些系統,一步一個腳印地重來一遍。

孔子曰:不聞不若聞之,聞之不若見之,見之不若知之,知之不若行之。

不聞不若聞之

聞之不若見之

見之不若知之,知之不若行之。

譯者註:上面原作者所引用的那段話在國外的翻譯是:I hear and I forget, I see and I remember, I do and I understand。外國人普遍認為出自孔子,但在查找這句英文的出處時,查到有篇博文稱這句話的中文實際出自荀子的《儒效篇》,經查確實如此。

我希望你讀到這裡的時候,已經認可了通過重新開發不同軟體系統來學習其原理這種方式。

《自己動手開發網路伺服器》會分為三個部分,將介紹如何從頭開發一個簡易網路伺服器。我們這就開始吧。

首先,到底什麼是網路伺服器?

簡而言之,它是在物理伺服器上搭建的一個網路連接伺服器(networking server),永久地等待客戶端發送請求。當伺服器收到請求之後,它會生成響應並將其返回至客戶端。客戶端與伺服器之間的通信,是以HTTP協議進行的。客戶端可以是瀏覽器,也可以是任何支持HTTP協議的軟體。

那麼,網路伺服器的簡單實現形式會是怎樣的呢?下面是我對此的理解。示例代碼使用Python語言實現,不過即使你不懂Python語言,你應該也可以從代碼和下面的解釋中理解相關的概念:

將上面的代碼保存為 ,或者直接從我的Github倉庫下載,然後通過命令行運行該文件:

接下來,在瀏覽器的地址欄輸入這個鏈接:http://localhost:8888/hello,然後按下回車鍵,你就會看見神奇的一幕。在瀏覽器中,應該會出現「Hello, World!」這句話:

是不是很神奇?接下來,我們來分析背後的實現原理。

首先,我們來看你所輸入的網路地址。它的名字叫URL(Uniform Resource Locator,統一資源定位符),其基本結構如下:

通過URL,你告訴了瀏覽器它所需要發現並連接的網路伺服器地址,以及獲取伺服器上的頁面路徑。不過在瀏覽器發送HTTP請求之前,它首先要與目標網路伺服器建立TCP連接。然後,瀏覽器再通過TCP連接發送HTTP請求至伺服器,並等待伺服器返回HTTP響應。當瀏覽器收到響應的時候,就會在頁面上顯示響應的內容,而在上面的例子中,瀏覽器顯示的就是「Hello, World!」這句話。

那麼,在客戶端發送請求、伺服器返迴響應之前,二者究竟是如何建立起TCP連接的呢?要建立起TCP連接,伺服器和客戶端都使用了所謂的套接字(socket)。接下來,我們不直接使用瀏覽器,而是在命令行使用 手動模擬瀏覽器。

在運行網路伺服器的同一台電腦上,通過命令行開啟一次 會話,將需要連接的主機設置為 ,主機的連接埠設置為 ,然後按回車鍵:

完成這些操作之後,你其實已經與本地運行的網路伺服器建立了TCP連接,隨時可以發送和接收HTTP信息。在下面這張圖片里,展示的是伺服器接受新TCP連接所需要完成的標準流程。

在上面那個 會話中,我們輸入 ,然後按下回車:

你成功地手動模擬了瀏覽器!你手動發送了一條HTTP請求,然後收到了HTTP響應。下面這幅圖展示的是HTTP請求的基本結構:

HTTP請求行包括了HTTP方法(這裡使用的是 方法,因為我們希望從伺服器獲取內容),伺服器頁面路徑( )以及HTTP協議的版本。

為了盡量簡化,我們目前實現的網路伺服器並不會解析上面的請求,你完全可以輸入一些沒有任何意義的代碼,也一樣可以收到"Hello, World!"響應。

在你輸入請求代碼並按下回車鍵之後,客戶端就將該請求發送至伺服器了,伺服器則會解析你發送的請求,並返回相應的HTTP響應。

下面這張圖顯示的是伺服器返回至客戶端的HTTP響應詳情:

我們來分析一下。響應中包含了狀態行 ,之後是必須的空行,然後是HTTP響應的正文。

響應的狀態行 中,包含了HTTP版本、HTTP狀態碼以及與狀態碼相對應的原因短語(Reason Phrase)。瀏覽器收到響應之後,會顯示響應的正文,這就是為什麼你會在瀏覽器中看到「Hello, World!」這句話。

這就是網路伺服器基本的工作原理了。簡單回顧一下:網路伺服器首先創建一個偵聽套接字(listening socket),並開啟一個永續循環接收新連接;客戶端啟動一個與伺服器的TCP連接,成功建立連接之後,向伺服器發送HTTP請求,之後伺服器返回HTTP響應。要建立TCP連接,客戶端和伺服器都使用了套接字。

現在,你已經擁有了一個基本可用的簡易網路伺服器,你可以使用瀏覽器或其他HTTP客戶端進行測試。正如上文所展示的,通過 命令並手動輸入HTTP請求,你自己也可以成為一個HTTP客戶端。

下面給大家布置一道思考題:如何在不對伺服器代碼作任何修改的情況下,通過該伺服器運行Djando應用、Flask應用和Pyramid應用,同時滿足這些不同網路框架的要求?

答案將在《自己動手開發網路伺服器》系列文章的第二部分揭曉。

回復下方「關鍵詞」,獲取優質資源

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 編程派 的精彩文章:

聊聊 print 的前世今生
沒了前端,後端開發怎麼辦?

TAG:編程派 |