【轉(zhuǎn)載】一起寫一個 Web 服務(wù)器(1)

有天一個女士出門散步,路過一個建筑工地,看到三個男人在干活。她問第一個男人,“你在干什么呢?”,第一個男人被問得很煩,咆哮道,“你沒看到我在碼磚嗎?”。她對回答不滿意,然后問第二個男人他在干什么。第二個男人回答,“我正在砌墻”,然后轉(zhuǎn)移注意力到第一個男人,他說,“嘿,你碼過頭了,你要把最后一塊磚拿掉?!薄K€是對回答不滿意,然后問第三個男人在干什么。第三個男人仰望著天空對她說,“我正在建造世界上最大的教堂?!?。當(dāng)他站在那里仰望天空的時候,另外兩個男人開始爭論磚位置不對的問題。第三個男人轉(zhuǎn)向前兩個男人說,“嘿,伙計們,別擔(dān)心那塊磚了,那是里面的墻,它會被灰泥堵塞起來,然后沒人會看到那塊磚。去另一層干活吧?!?/p>

故事的寓意是說,當(dāng)你了解整個系統(tǒng),理解不同的部分如何組織到一起的(磚、墻、教堂),你就能找出問題并快速解決之(磚位置不對)。

這跟從零開始搭建你的WEB服務(wù)器有什么關(guān)系呢?

我相信,要成為優(yōu)秀的開發(fā)者,你必須對你每天都用的底層的軟件系統(tǒng)有進一步的理解,包括編程語言、編譯器和解釋器、數(shù)據(jù)庫和操作系統(tǒng)、WEB服務(wù)器和WEB框架。為了更好更深入的理解這些系統(tǒng),你可以從零開始一塊磚地,一面墻地,重建它們。

子曰:聞之我也野,視之我也饒,行之我也明

image

“我看過的,我還記得?!?/p>

image

“我做過的,我都理解了?!?/p>

image

(子曰:聞之我也野,視之我也饒,行之我也明)

此時我希望你能夠相信,從重建不同的軟件系統(tǒng)來開始來學(xué)習(xí)它們是如何工作的,是一個好主意。

在這個由3部分組成的系列文章中,我會向你展示怎樣搭建一個基本的WEB服務(wù)器。咱們開始吧。

重中之重,什么是WEB服務(wù)器?

image

簡而言之,它是一個位于一個物理服務(wù)器上的網(wǎng)絡(luò)服務(wù)器(呀,服務(wù)器上的服務(wù)器),它等待客戶端發(fā)送請求。當(dāng)它接收到一個請求,就會生成一個響應(yīng)并回發(fā)給客戶端??蛻舳撕头?wù)器使用HTTP協(xié)議通信??蛻舳丝梢允菫g覽器或者別的使用HTTP協(xié)議的軟件。

一個非常簡單的WEB服務(wù)器實現(xiàn)長什么樣呢?以下是我寫的一個。例子是用Python語言寫的,但是即使你不會Python(它是一個非常易學(xué)的語言,試試?。闳匀豢梢酝ㄟ^代碼和下面的解釋理解相關(guān)概念:

import socket
 
HOST, PORT = '', 8888
 
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind((HOST, PORT))
listen_socket.listen(1)
print 'Serving HTTP on port %s ...' % PORT
while True:
    client_connection, client_address = listen_socket.accept()
    request = client_connection.recv(1024)
    print request
 
    http_response = """
HTTP/1.1 200 OK
 
Hello, World!
"""
    client_connection.sendall(http_response)
    client_connection.close()

把上面的代碼保存到webserver1.py或者直接從GitHub下載,然后像下面這樣在命令行運行它

$ python webserver1.py
Serving HTTP on port 8888 …

現(xiàn)在在你的WEB瀏覽器地址欄里輸入以下URL http://localhost:8888/hello,敲回車,見證奇跡的時刻。你會看到瀏覽器顯示”Hello, World!“,像這樣:

image

認真做一下吧,我會等你的。

做完了?很好?,F(xiàn)在我們討論一下它到底怎么工作的。

首先我們從你剛才鍵入的WEB地址開始。它叫URL,這是它的基本結(jié)構(gòu):

image

這個就表示怎樣告訴瀏覽器要查找和連接的WEB服務(wù)器地址,和你要獲取的服務(wù)器上的頁面(路徑)。但是在瀏覽器發(fā)送HTTP請求前,瀏覽器需要先和WEB服務(wù)器建立TCP連接。然后瀏覽器在TCP連接上發(fā)送HTTP請求,然后等待服務(wù)器回發(fā)HTTP響應(yīng)。當(dāng)瀏覽器接收到響應(yīng)后,顯示響應(yīng),在本次例子中,瀏覽器顯示“Hello, World!”。

我們再詳細探索一下客戶端和服務(wù)器在發(fā)送HTTP請求和響應(yīng)前如何建立TCP連接的。在建立連接,它們必須使用所謂的sockets。用你命令行下的telnet手動模擬瀏覽器吧,而不是直接使用瀏覽器。

在運行WEB服務(wù)器的同一臺電腦上,在命令行啟動一個telnet會話,指定連接到localhost主機,連接端口為8888,然后按回車:

$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.

此時,你已經(jīng)和運行在你本地主機的服務(wù)器建立了TCP連接,已經(jīng)準(zhǔn)備好發(fā)送并接收HTTP消息了。下圖中你可以看到一個服務(wù)器要經(jīng)過的標(biāo)準(zhǔn)步驟,然后才能接受新的TCP連接。

image

在同一個telnet會話中,輸入 GET /hello HTTP/1.1然后敲回車:

$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.
GET /hello HTTP/1.1

HTTP/1.1 200 OK
Hello, World!

你完成了手動模擬瀏覽器!你發(fā)送了一個HTTP請求并得到了一個HTTP響應(yīng)。這是HTTP請求的基本結(jié)構(gòu):

image

HTTP請求由行組成。行指示了HTTP方法(GET,因為我們請求我們的服務(wù)器返回給我們一些東西)、代表我們想要的服務(wù)器上的“頁面”的路徑 /hello和協(xié)議版本。

為了簡單起見,此時我們的WEB服務(wù)器完全忽略了上面的請求行。你也可以輸入任何垃圾字符取代“GET /hello HTTP/1.1”,你仍然會得到“Hello, World!”響應(yīng)。

一旦你輸入了請求行,敲了回車,客戶端就發(fā)送請求給服務(wù)器,服務(wù)器讀取請求行,打印出來然后返回相應(yīng)的HTTP響應(yīng)。

以下是服務(wù)器回發(fā)給客戶端(這個例子中是telnet)的HTTP響應(yīng):

image

咱們分析一下它,響應(yīng)包含了狀態(tài)行HTTP/1.1 200 OK,隨后一個必須的空行,和HTTP響應(yīng)body。

響應(yīng)狀態(tài)行TTP/1.1 200 OK包含了HTTP版本,HTTP狀態(tài)碼和HTTP狀態(tài)碼理由短語OK。瀏覽器得到響應(yīng)時,它就顯示響應(yīng)的body,所以你就看到了“Hello, World!”

這就是WEB瀏覽器怎么工作的基本模型??偨Y(jié)來說:WEB服務(wù)器創(chuàng)建一個監(jiān)聽socket然后開始循環(huán)接受新連接。客戶端初始化一個TCP連接,在連接成功后,客戶端發(fā)送HTTP請求到服務(wù)器,服務(wù)器響應(yīng)一個顯示給用戶的HTTP響應(yīng)。客戶端和服務(wù)器都使用socket建立TCP連接。

你現(xiàn)在你擁有了一個非?;A(chǔ)的WEB服務(wù)器,你可以用瀏覽器或其他的HTTP客戶端測試它。正如你看到的,使用telnet手動輸入HTTP請求,你也就成了一個人肉 HTTP 客戶端。

對你來說有一個問題:“怎樣在你的剛完成的WEB服務(wù)器下運行 Django 應(yīng)用、Flask 應(yīng)用和 Pyramid 應(yīng)用?在不單獨修改服務(wù)器來適應(yīng)這些不同的 WEB 框架的情況下?!?/p>

我會在本系列的第 2 部分秀給你看的。請保持關(guān)注哦。

順便說下,我在寫一本書《一起構(gòu)建WEB服務(wù)器:第一步》,它解釋了從零開始寫一個基本的WEB服務(wù)器,還更詳細地講解了我上面提到的話題。訂閱郵件組來獲取關(guān)于書籍和發(fā)布時間和最近更新。


靈感來自于 Lead with a Story: A Guide to Crafting Business Narratives That Captivate, Convince, and Inspire

本文轉(zhuǎn)載地址:http://python.jobbole.com/81524/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容