有天一個(gè)女士出門散步狸眼,路過一個(gè)建筑工地泌射,看到三個(gè)男人在干活。她問第一個(gè)男人,“你在干什么呢钧大?”读规,第一個(gè)男人被問得很煩宜咒,咆哮道幌绍,“你沒看到我在碼磚嗎?”趾牧。她對回答不滿意检盼,然后問第二個(gè)男人他在干什么。第二個(gè)男人回答翘单,“我正在砌墻”吨枉,然后轉(zhuǎn)移注意力到第一個(gè)男人,他說哄芜,“嘿貌亭,你碼過頭了,你要把最后一塊磚拿掉认臊∑酝ィ”。她還是對回答不滿意,然后問第三個(gè)男人在干什么剧腻。第三個(gè)男人仰望著天空對她說拘央,“我正在建造世界上最大的教堂∈樵冢”灰伟。當(dāng)他站在那里仰望天空的時(shí)候,另外兩個(gè)男人開始爭論磚位置不對的問題儒旬。第三個(gè)男人轉(zhuǎn)向前兩個(gè)男人說栏账,“嘿,伙計(jì)們栈源,別擔(dān)心那塊磚了挡爵,那是里面的墻,它會(huì)被灰泥堵塞起來凉翻,然后沒人會(huì)看到那塊磚了讨。去另一層干活吧捻激≈坪洌“
故事的寓意是說,當(dāng)你了解整個(gè)系統(tǒng)胞谭,理解不同的部分如何組織到一起的(磚垃杖、墻、教堂)丈屹,你就能找出問題并快速解決之(磚位置不對)调俘。
這跟從零開始搭建你的WEB服務(wù)器有什么關(guān)系呢?
我相信旺垒,要成為優(yōu)秀的開發(fā)者彩库,你必須對你每天都用的底層的軟件系統(tǒng)有進(jìn)一步的理解,包括編程語言先蒋、編譯器和解釋器骇钦、數(shù)據(jù)庫和操作系統(tǒng)、WEB服務(wù)器和WEB框架竞漾。為了更好更深入的理解這些系統(tǒng)眯搭,你可以從零開始一塊磚地,一面墻地业岁,重建它們鳞仙。
子曰:聞之我也野,視之我也饒笔时,行之我也明
“我看過的棍好,我還記得。”
“我做過的借笙,我都理解了爹梁。”
(子曰:聞之我也野提澎,視之我也饒姚垃,行之我也明)
此時(shí)我希望你能夠相信,從重建不同的軟件系統(tǒng)來開始來學(xué)習(xí)它們是如何工作的盼忌,是一個(gè)好主意积糯。
在這個(gè)由3部分組成的系列文章中,我會(huì)向你展示怎樣搭建一個(gè)基本的WEB服務(wù)器谦纱。咱們開始吧看成。
重中之重,什么是WEB服務(wù)器跨嘉?
簡而言之川慌,它是一個(gè)位于一個(gè)物理服務(wù)器上的網(wǎng)絡(luò)服務(wù)器(呀,服務(wù)器上的服務(wù)器)祠乃,它等待客戶端發(fā)送請求梦重。當(dāng)它接收到一個(gè)請求,就會(huì)生成一個(gè)響應(yīng)并回發(fā)給客戶端亮瓷∏倥。客戶端和服務(wù)器使用HTTP協(xié)議通信≈鲋В客戶端可以是瀏覽器或者別的使用HTTP協(xié)議的軟件蚓胸。
一個(gè)非常簡單的WEB服務(wù)器實(shí)現(xiàn)長什么樣呢?以下是我寫的一個(gè)除师。例子是用Python語言寫的沛膳,但是即使你不會(huì)Python(它是一個(gè)非常易學(xué)的語言,試試Q淳邸)锹安,你仍然可以通過代碼和下面的解釋理解相關(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下載,然后像下面這樣在命令行運(yùn)行它
$ python webserver1.py
Serving HTTP on port 8888 …
現(xiàn)在在你的WEB瀏覽器地址欄里輸入以下URL http://localhost:8888/hello贞岭,敲回車八毯,見證奇跡的時(shí)刻。你會(huì)看到瀏覽器顯示”Hello, World!“瞄桨,像這樣:
認(rèn)真做一下吧话速,我會(huì)等你的。
做完了芯侥?很好〔唇唬現(xiàn)在我們討論一下它到底怎么工作的乳讥。
首先我們從你剛才鍵入的WEB地址開始。它叫URL廓俭,這是它的基本結(jié)構(gòu):
這個(gè)就表示怎樣告訴瀏覽器要查找和連接的WEB服務(wù)器地址云石,和你要獲取的服務(wù)器上的頁面(路徑)。但是在瀏覽器發(fā)送HTTP請求前研乒,瀏覽器需要先和WEB服務(wù)器建立TCP連接汹忠。然后瀏覽器在TCP連接上發(fā)送HTTP請求,然后等待服務(wù)器回發(fā)HTTP響應(yīng)雹熬。當(dāng)瀏覽器接收到響應(yīng)后宽菜,顯示響應(yīng),在本次例子中竿报,瀏覽器顯示“Hello, World!”铅乡。
我們再詳細(xì)探索一下客戶端和服務(wù)器在發(fā)送HTTP請求和響應(yīng)前如何建立TCP連接的。在建立連接烈菌,它們必須使用所謂的sockets阵幸。用你命令行下的telnet手動(dòng)模擬瀏覽器吧,而不是直接使用瀏覽器芽世。
在運(yùn)行WEB服務(wù)器的同一臺(tái)電腦上挚赊,在命令行啟動(dòng)一個(gè)telnet會(huì)話,指定連接到localhost主機(jī)捂襟,連接端口為8888咬腕,然后按回車:
$ telnet localhost 8888
Trying 127.0.0.1 …
Connected to localhost.
此時(shí)欢峰,你已經(jīng)和運(yùn)行在你本地主機(jī)的服務(wù)器建立了TCP連接葬荷,已經(jīng)準(zhǔn)備好發(fā)送并接收HTTP消息了。下圖中你可以看到一個(gè)服務(wù)器要經(jīng)過的標(biāo)準(zhǔn)步驟纽帖,然后才能接受新的TCP連接宠漩。
在同一個(gè)telnet會(huì)話中,輸入 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!
你完成了手動(dòng)模擬瀏覽器懊直!你發(fā)送了一個(gè)HTTP請求并得到了一個(gè)HTTP響應(yīng)扒吁。這是HTTP請求的基本結(jié)構(gòu):
HTTP請求由行組成。行指示了HTTP方法(GET室囊,因?yàn)槲覀冋埱笪覀兊姆?wù)器返回給我們一些東西)雕崩、代表我們想要的服務(wù)器上的“頁面”的路徑 /hello和協(xié)議版本。
為了簡單起見融撞,此時(shí)我們的WEB服務(wù)器完全忽略了上面的請求行盼铁。你也可以輸入任何垃圾字符取代“GET /hello HTTP/1.1”,你仍然會(huì)得到“Hello, World!”響應(yīng)尝偎。
一旦你輸入了請求行饶火,敲了回車鹏控,客戶端就發(fā)送請求給服務(wù)器,服務(wù)器讀取請求行肤寝,打印出來然后返回相應(yīng)的HTTP響應(yīng)当辐。
以下是服務(wù)器回發(fā)給客戶端(這個(gè)例子中是telnet)的HTTP響應(yīng):
咱們分析一下它,響應(yīng)包含了狀態(tài)行HTTP/1.1 200 OK鲤看,隨后一個(gè)必須的空行缘揪,和HTTP響應(yīng)body。
響應(yīng)狀態(tài)行TTP/1.1 200 OK包含了HTTP版本义桂,HTTP狀態(tài)碼和HTTP狀態(tài)碼理由短語OK寺晌。瀏覽器得到響應(yīng)時(shí),它就顯示響應(yīng)的body澡刹,所以你就看到了“Hello, World呻征!”
這就是WEB瀏覽器怎么工作的基本模型“战剑總結(jié)來說:WEB服務(wù)器創(chuàng)建一個(gè)監(jiān)聽socket然后開始循環(huán)接受新連接陆赋。客戶端初始化一個(gè)TCP連接嚷闭,在連接成功后攒岛,客戶端發(fā)送HTTP請求到服務(wù)器,服務(wù)器響應(yīng)一個(gè)顯示給用戶的HTTP響應(yīng)胞锰≡志猓客戶端和服務(wù)器都使用socket建立TCP連接。
你現(xiàn)在你擁有了一個(gè)非承衢牛基礎(chǔ)的WEB服務(wù)器顺饮,你可以用瀏覽器或其他的HTTP客戶端測試它。正如你看到的凌那,使用telnet手動(dòng)輸入HTTP請求兼雄,你也就成了一個(gè)人肉 HTTP 客戶端。
對你來說有一個(gè)問題:“怎樣在你的剛完成的WEB服務(wù)器下運(yùn)行 Django 應(yīng)用帽蝶、Flask 應(yīng)用和 Pyramid 應(yīng)用赦肋?在不單獨(dú)修改服務(wù)器來適應(yīng)這些不同的 WEB 框架的情況下±龋”
我會(huì)在本系列的第 2 部分秀給你看的佃乘。請保持關(guān)注哦。
順便說下驹尼,我在寫一本書《一起構(gòu)建WEB服務(wù)器:第一步》趣避,它解釋了從零開始寫一個(gè)基本的WEB服務(wù)器,還更詳細(xì)地講解了我上面提到的話題扶欣。訂閱郵件組來獲取關(guān)于書籍和發(fā)布時(shí)間和最近更新鹅巍。
靈感來自于 Lead with a Story: A Guide to Crafting Business Narratives That Captivate, Convince, and Inspire